2019-11-26 Martin Rudalics <rudalics@gmx.at>

* 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'.
This commit is contained in:
Martin Rudalics 2019-11-26 10:13:12 +01:00
parent b006095bc9
commit 261b060f12
3 changed files with 199 additions and 51 deletions

View file

@ -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.
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-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}.
@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

View file

@ -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

View file

@ -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))))
(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)))))
;; 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)))
(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.