From 261b060f12234baa6912ef40a9ce1a054f583ad0 Mon Sep 17 00:00:00 2001 From: Martin Rudalics Date: Tue, 26 Nov 2019 10:13:12 +0100 Subject: [PATCH] 2019-11-26 Martin Rudalics * lisp/window.el (switch-to-visible-buffer): Declare obsolete. (switch-to-prev-buffer-skip): New option. (switch-to-prev-buffer, switch-to-next-buffer): Obey 'switch-to-prev-buffer-skip'. * doc/lispref/windows.texi (Window History): Remove description of 'switch-to-visible-buffer'. Describe new option 'switch-to-prev-buffer-skip' * etc/NEWS: Mention switch from 'switch-to-visible-buffer' to 'switch-to-prev-buffer-skip'. --- doc/lispref/windows.texi | 78 ++++++++++++++---- etc/NEWS | 10 +++ lisp/window.el | 166 ++++++++++++++++++++++++++++++--------- 3 files changed, 201 insertions(+), 53 deletions(-) diff --git a/doc/lispref/windows.texi b/doc/lispref/windows.texi index f05a6db1761..fdba259bf71 100644 --- a/doc/lispref/windows.texi +++ b/doc/lispref/windows.texi @@ -3920,8 +3920,13 @@ or killed, or has been already shown by a recent invocation of If repeated invocations of this command have already shown all buffers previously shown in @var{window}, further invocations will show buffers from the buffer list of the frame @var{window} appears on (@pxref{Buffer -List}), trying to skip buffers that are already shown in another window -on that frame. +List}). + +The option @code{switch-to-prev-buffer-skip} described below can be +used to inhibit switching to certain buffers, for example, to those +already shown in another window. Also, if @var{window}'s frame has a +@code{buffer-predicate} parameter (@pxref{Buffer Parameters}), that +predicate may inhibit switching to certain buffers. @end deffn @deffn Command switch-to-next-buffer &optional window @@ -3933,20 +3938,65 @@ defaults to the selected one. If there is no recent invocation of @code{switch-to-prev-buffer} that can be undone, this function tries to show a buffer from the buffer list of the frame @var{window} appears on (@pxref{Buffer List}). + +The option @code{switch-to-prev-buffer-skip} and the +@code{buffer-predicate} (@pxref{Buffer Parameters}) of @var{window}'s +frame affect this command as they do for @code{switch-to-prev-buffer}. @end deffn -By default @code{switch-to-prev-buffer} and @code{switch-to-next-buffer} -can switch to a buffer that is already shown in another window on the -same frame. The following option can be used to override this behavior. - -@defopt switch-to-visible-buffer -If this variable is non-@code{nil}, @code{switch-to-prev-buffer} and -@code{switch-to-next-buffer} may switch to a buffer that is already -visible on the same frame, provided the buffer was shown in the -relevant window before. If it is @code{nil}, -@code{switch-to-prev-buffer} and @code{switch-to-next-buffer} always -try to avoid switching to a buffer that is already visible in another -window on the same frame. The default is @code{t}. +By default @code{switch-to-prev-buffer} and +@code{switch-to-next-buffer} can switch to a buffer that is already +shown in another window. The following option can be used to override +this behavior. + +@defopt switch-to-prev-buffer-skip +If this variable is @code{nil}, @code{switch-to-prev-buffer} may +switch to any buffer, including those already shown in other windows. + +If this variable is non-@code{nil}, @code{switch-to-prev-buffer} will +refrain from switching to certain buffers. The following values can +be used: + +@itemize @bullet +@item +@code{this} means do not switch to a buffer shown on the frame that +hosts the window @code{switch-to-prev-buffer} is acting upon. + +@item +@code{visible} means do not switch to a buffer shown on any visible +frame. + +@item +0 (the number zero) means do not switch to a buffer shown on any +visible or iconified frame. + +@item +@code{t} means do not switch to a buffer shown on any live frame. + +@item +A function that takes three arguments---the @var{window} argument of +@code{switch-to-prev-buffer}, a buffer @code{switch-to-prev-buffer} +intends to switch to and the @var{bury-or-kill} argument of +@code{switch-to-prev-buffer}. If that function returns +non-@code{nil}, @code{switch-to-prev-buffer} will refrain from +switching to the buffer specified by the second argument. +@end itemize + +The command @code{switch-to-next-buffer} obeys this option in a +similar way. If this option specifies a function, +@code{switch-to-next-buffer} will call that function with the third +argument always @code{nil}. + +Note that since @code{switch-to-prev-buffer} is called by +@code{bury-buffer}, @code{replace-buffer-in-windows} and +@code{quit-restore-window} as well, customizing this option may also +affect the behavior of Emacs when a window is quit or a buffer gets +buried or killed. + +Note also that under certain circumstances +@code{switch-to-prev-buffer} and @code{switch-to-next-buffer} may +ignore this option, for example, when there is only one buffer left +these functions can switch to. @end defopt diff --git a/etc/NEWS b/etc/NEWS index a97cf20ea7c..2a14eb2ecfc 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -414,6 +414,16 @@ When non-nil, 'switch-to-buffer' uses 'pop-to-buffer-same-window' that respects display actions specified by 'display-buffer-alist' and 'display-buffer-overriding-action'. ++++ +** The option 'switch-to-visible-buffer' is now obsolete. +Customize 'switch-to-prev-buffer-skip' instead. + ++++ +** New option 'switch-to-prev-buffer-skip'. +This option allows to specify the set of buffers that may be shown by +'switch-to-prev-buffer' and 'switch-to-next-buffer' more stringently +than the now obsolete 'switch-to-visible-buffer'. + ** New 'flex' completion style An implementation of popular "flex/fuzzy/scatter" completion which matches strings where the pattern appears as a subsequence. Put diff --git a/lisp/window.el b/lisp/window.el index 74780479393..49fad75d3cd 100644 --- a/lisp/window.el +++ b/lisp/window.el @@ -4409,6 +4409,68 @@ that is already visible in another window on the same frame." :version "24.1" :group 'windows) +(make-obsolete-variable 'switch-to-visible-buffer + 'switch-to-prev-buffer-skip "27.1") + +(defcustom switch-to-prev-buffer-skip nil + "Buffers `switch-to-prev-buffer' should skip. +If this variable is nil, `switch-to-prev-buffer' may switch to +any buffer, including those already shown in other windows. + +If this variable is non-nil, `switch-to-prev-buffer' will refrain +from switching to certain buffers according to the value of this +variable: + +- `this' means do not switch to a buffer shown on the frame that + hosts the window `switch-to-prev-buffer' is acting upon. + +- `visible' means do not switch to a buffer shown on any visible + frame. + +- 0 (the number zero) means do not switch to a buffer shown on + any visible or iconified frame. + +- t means do not switch to a buffer shown on any live frame. + +If this option specifies a function, that function is called with +three arguments - the WINDOW argument of `switch-to-prev-buffer', +a buffer `switch-to-prev-buffer' intends to switch to and the +BURY-OR-KILL argument of `switch-to-prev-buffer'. If that +function returns non-nil, `switch-to-prev-buffer' will not switch +to that buffer. + +Since `switch-to-prev-buffer' is called by `bury-buffer', +`replace-buffer-in-windows' and `quit-restore-window' among +others, customizing this option may also affect the behavior of +Emacs when a window is quit or a buffer gets buried or killed. + +The value of this option is consulted by `switch-to-next-buffer' +as well. In that case, if this option specifies a function, it +will be called with the third argument nil. + +Under certain circumstances `switch-to-prev-buffer' may ignore +this option, for example, when there is only one buffer left." + :type + '(choice (const :tag "Never" nil) + (const :tag "This frame" this) + (const :tag "Visible frames" visible) + (const :tag "Visible and iconified frames" 0) + (const :tag "Any frame" t) + (function :tag "Function")) + :version "27.1" + :group 'windows) + +(defun switch-to-prev-buffer-skip-p (skip window buffer &optional bury-or-kill) + "Return non-nil if `switch-to-prev-buffer' should skip BUFFER. +SKIP is a value derived from `switch-to-prev-buffer-skip', WINDOW +the window `switch-to-prev-buffer' acts upon. Optional argument +BURY-OR-KILL is passed unchanged by `switch-to-prev-buffer' and +omitted in calls from `switch-to-next-buffer'." + (when skip + (if (functionp skip) + (funcall skip window buffer bury-or-kill) + (get-buffer-window buffer skip)))) + (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. @@ -4424,6 +4486,12 @@ 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. +The option `switch-to-prev-buffer-skip' can be used to not switch +to certain buffers, for example, to those already shown in +another window. Also, if WINDOW's frame has a `buffer-predicate' +parameter, that predicate may inhibit switching to certain +buffers. + This function is called by `prev-buffer'." (interactive) (let* ((window (window-normalize-window window t)) @@ -4433,7 +4501,15 @@ This function is called by `prev-buffer'." ;; 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) + (skip + (cond + ((or (functionp switch-to-prev-buffer-skip) + (memq switch-to-prev-buffer-skip '(t visible 0))) + switch-to-prev-buffer-skip) + ((or switch-to-prev-buffer-skip + (not switch-to-visible-buffer)) + frame))) + entry new-buffer killed-buffers skipped) (when (window-minibuffer-p window) ;; Don't switch in minibuffer window. (unless (setq window (minibuffer-selected-window)) @@ -4456,11 +4532,8 @@ This function is called by `prev-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) + (if (switch-to-prev-buffer-skip-p skip window new-buffer bury-or-kill) + (setq skipped new-buffer) (set-window-buffer-start-and-point window new-buffer (nth 1 entry) (nth 2 entry)) (throw 'found t)))) @@ -4478,18 +4551,17 @@ This function is called by `prev-buffer'." (when (and (buffer-live-p buffer) (not (eq buffer old-buffer)) (or (null pred) (funcall pred buffer)) + ;; Skip buffers whose names start with a space. (not (eq (aref (buffer-name buffer) 0) ?\s)) - ;; Don't show a buffer shown in a side window before. + ;; Skip buffers shown in a side window before. (not (buffer-local-value 'window--sides-shown buffer)) (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 window. - (unless visible - (setq visible buffer)) + (if (switch-to-prev-buffer-skip-p skip window buffer bury-or-kill) + (setq skipped (or skipped 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!). @@ -4502,14 +4574,16 @@ This function is called by `prev-buffer'." (not (eq buffer old-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) + (if (switch-to-prev-buffer-skip-p skip window buffer bury-or-kill) + (setq skipped (or skipped buffer)) + (setq new-buffer buffer) + (set-window-buffer-start-and-point + window new-buffer (nth 1 entry) (nth 2 entry)) + (throw 'found t))))) + + (when skipped + ;; Show first skipped buffer. + (setq new-buffer skipped) (set-window-buffer-start-and-point window new-buffer))) (if bury-or-kill @@ -4547,7 +4621,15 @@ This function is called by `prev-buffer'." "In WINDOW switch to next 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. This function is called by `next-buffer'." +found. + +The option `switch-to-prev-buffer-skip' can be used to not switch +to certain buffers, for example, to those already shown in +another window. Also, if WINDOW's frame has a `buffer-predicate' +parameter, that predicate may inhibit switching to certain +buffers. + +This function is called by `next-buffer'." (interactive) (let* ((window (window-normalize-window window t)) (frame (window-frame window)) @@ -4555,7 +4637,15 @@ found. This function is called by `next-buffer'." (old-buffer (window-buffer window)) (next-buffers (window-next-buffers window)) (pred (frame-parameter frame 'buffer-predicate)) - new-buffer entry killed-buffers visible) + (skip + (cond + ((or (functionp switch-to-prev-buffer-skip) + (memq switch-to-prev-buffer-skip '(t visible 0))) + switch-to-prev-buffer-skip) + ((or switch-to-prev-buffer-skip + (not switch-to-visible-buffer)) + frame))) + new-buffer entry killed-buffers skipped) (when (window-minibuffer-p window) ;; Don't switch in minibuffer window. (unless (setq window (minibuffer-selected-window)) @@ -4574,10 +4664,12 @@ found. This function is called by `next-buffer'." (not (eq buffer old-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))) + (if (switch-to-prev-buffer-skip-p skip window buffer) + (setq skipped buffer) + (setq new-buffer buffer) + (set-window-buffer-start-and-point + window new-buffer (nth 1 entry) (nth 2 entry)) + (throw 'found t)))) ;; Scan the buffer list of WINDOW's frame next, skipping previous ;; buffers entries. Skip this step for side windows. (unless window-side @@ -4585,14 +4677,13 @@ found. This function is called by `next-buffer'." (when (and (buffer-live-p buffer) (not (eq buffer old-buffer)) (or (null pred) (funcall pred buffer)) + ;; Skip buffers whose names start with a space. (not (eq (aref (buffer-name buffer) 0) ?\s)) - ;; Don't show a buffer shown in a side window before. + ;; Skip buffers shown in a side window before. (not (buffer-local-value 'window--sides-shown buffer)) (not (assq buffer (window-prev-buffers window)))) - (if (and (not switch-to-visible-buffer) - (get-buffer-window buffer frame)) - ;; Try to avoid showing a buffer visible in some other window. - (setq visible buffer) + (if (switch-to-prev-buffer-skip-p skip window buffer) + (setq skipped (or skipped buffer)) (setq new-buffer buffer) (set-window-buffer-start-and-point window new-buffer) (throw 'found t))))) @@ -4605,18 +4696,15 @@ found. This function is called by `next-buffer'." (cons new-buffer killed-buffers)))) (not (eq new-buffer old-buffer)) (or (null pred) (funcall pred new-buffer))) - (if (and (not switch-to-visible-buffer) - (get-buffer-window new-buffer frame)) - ;; Try to avoid showing a buffer visible in some other window. - (unless visible - (setq visible new-buffer)) + (if (switch-to-prev-buffer-skip-p skip window new-buffer) + (setq skipped (or skipped new-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) + (when skipped + ;; Show first skipped buffer. + (setq new-buffer skipped) (set-window-buffer-start-and-point window new-buffer))) ;; Remove `new-buffer' from and restore WINDOW's next buffers. -- 2.39.5