[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
bug#69993: Wrap window buffers while cycling
From: |
Juri Linkov |
Subject: |
bug#69993: Wrap window buffers while cycling |
Date: |
Thu, 28 Mar 2024 09:54:31 +0200 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/30.0.50 (x86_64-pc-linux-gnu) |
>>> I'm not sure I understand. IIRC 'window-next-buffers' always returns
>>> nil unless you invoked 'switch-to-prev-buffer' before. It serves to
>>> "navigate" a window's buffer list, in particular, to "undo" preceding
>>> 'previous-buffer' calls when overshooting. 'switch-to-buffer' is not
>>> part of such a scenario.
>>
>> A new option should always keep the fixed order, even when users use C-x b
>> to visit a buffer that appeared in the window before.
>
> What is the "fixed order"? When I use C-x b, that buffer becomes the
> one most recently shown in that window.
The fixed order is similar to how tabs work in web browsers.
It would be unexpected when switching to a tab will always
move it to the end of the tab line. This is why it's unexpected
for C-x b to move tabs when tab-line-mode is used.
>> The problem is that there is no function that is called after
>> set-window-buffer to reset the order of prev/next-buffers.
>>
>> set-window-buffer works that way that before changing the window buffer
>> it calls record-window-buffer. But record-window-buffer has
>> no information about new-buffer. So it can't reorder prev/next-buffers
>> based on new-buffer that will be displayed in this window.
>>
>> Then later set-window-buffer sets window's buffer,
>> but after that it doesn't call any function like
>> record-window-buffer that could reorder prev/next-buffers.
>>
>> Then maybe possible to add such reordering after calling
>> set-window-buffer? I mean such places as after calling
>> set-window-buffer in window--display-buffer, and after calling
>> set-window-buffer in switch-to-buffer.
>
> Then give 'record-window-buffer' a second argument - the new buffer to
> be shown. I'm a bit reluctant to work in this area - the introduction
> of 'push-window-buffer-onto-prev' has obfuscated the code considerably
> for no apparent use (at least one that I could understand).
Ok, let's add a second argument to 'record-window-buffer'.
I'll do this in a separate feature request for a new option
that will keep the fixed order for C-x b
since it's quite different from the wrapping option.
> I see no problems with it. After C-x b *foo* I want to return to *foo*
> via 'previous-buffer' after switching to *bar* via a second C-x b. What
> would you want to see instead? Maybe I still misunderstand you.
Selecting a buffer via C-x b still uses the sorting order of buffers
by the most-recently-used. So after C-x b *bar* you still can easily
return to *foo* by C-x b RET. But the proposed change makes sense
when using tab-line-mode where C-x b messes up buffer tabs.
> I think 'switch-to-prev-buffer-wrap' already confuses things. Wrapping,
> for me, means to wrap around like when navigating on a ring of buffers.
> Whether this should include buffers never shown in the window before is
> a different issue IMO. And whether C-x b should change the order is yet
> another issue. So maybe we need three options instead of one...
I can't imagine why anyone would need wrapping when C-x C-left
will visit hundreds of buffers never shown in the window.
So we need only two options: wrapping buffers shown in the window,
and to keep the fixed order of C-x b. So I will create a new request
for the fixed order of C-x b. And here is the final patch for wrapping:
diff --git a/lisp/window.el b/lisp/window.el
index df55a7ca673..ff08b0bcfc9 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -4542,6 +4546,22 @@ set-window-buffer-start-and-point
(when point
(set-window-point window point))))
+(defcustom switch-to-prev-buffer-wrap nil
+ "Wrap to the first or last window buffer while cycling.
+The value t means wrapping around while cycling buffers appeared in the
+window before. So when the commands that switch buffers in the selected
+window `previous-buffer' and `next-buffer' reach the first or the last
+buffer (these buffers are visible when using `tab-line-mode'),
+then wrap around to another end of the list of previous/next buffers.
+
+When the value is `stop', stop at the first or last buffer
+in the list of previous/next buffers, but don't wrap around."
+ :type '(choice (const :tag "Never wrap" nil)
+ (const :tag "Stop at window-local buffers" stop)
+ (const :tag "Wrap to window-local buffers" t))
+ :version "30.1"
+ :group 'windows)
+
(defcustom switch-to-visible-buffer t
"If non-nil, allow switching to an already visible buffer.
If this variable is non-nil, `switch-to-prev-buffer' and
@@ -4676,7 +4696,7 @@ switch-to-prev-buffer
((or switch-to-prev-buffer-skip
(not switch-to-visible-buffer))
frame)))
- entry new-buffer killed-buffers skipped)
+ entry new-buffer killed-buffers skipped wrapped)
(when (window-minibuffer-p window)
;; Don't switch in minibuffer window.
(unless (setq window (minibuffer-selected-window))
@@ -4710,8 +4730,8 @@ switch-to-prev-buffer
;; 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
+ ;; this step for side windows or when wrapping.
+ (unless (or window-side switch-to-prev-buffer-wrap)
(dolist (buffer (if bury-or-kill
(buffer-list frame)
(nreverse (buffer-list frame))))
@@ -4729,7 +4749,9 @@ switch-to-prev-buffer
(set-window-buffer-start-and-point window new-buffer)
(throw 'found t)))))
- (unless bury-or-kill
+ (when (eq switch-to-prev-buffer-wrap 'stop)
+ (setq wrapped 'stop))
+ (unless (or bury-or-kill (eq switch-to-prev-buffer-wrap 'stop))
;; Scan reverted next buffers last (must not use nreverse
;; here!).
(dolist (buffer (reverse next-buffers))
@@ -4743,12 +4765,13 @@ switch-to-prev-buffer
(setq entry (assq buffer (window-prev-buffers window))))
(if (switch-to-prev-buffer-skip-p skip window buffer bury-or-kill)
(setq skipped (or skipped buffer))
- (setq new-buffer buffer)
+ (setq new-buffer buffer wrapped t)
(set-window-buffer-start-and-point
window new-buffer (nth 1 entry) (nth 2 entry))
(throw 'found t)))))
- (when (and skipped (not (functionp switch-to-prev-buffer-skip)))
+ (when (and skipped (not (functionp switch-to-prev-buffer-skip))
+ (not wrapped))
;; Show first skipped buffer, unless skip was a function.
(setq new-buffer skipped)
(set-window-buffer-start-and-point window new-buffer)))
@@ -4768,10 +4791,28 @@ switch-to-prev-buffer
;; 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))))
+ (if (not (and switch-to-prev-buffer-wrap wrapped))
+ ;; 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)))
+ (if (eq wrapped 'stop)
+ (setq new-buffer nil)
+ ;; Restore the right order of previous buffers.
+ (let ((prev-buffers (window-prev-buffers window)))
+ ;; Use the same sorting order as was in next-buffers
+ ;; with old-buffer at the bottom.
+ (setq prev-buffers
+ (sort prev-buffers
+ (lambda (a b)
+ (cond
+ ((eq (car a) old-buffer) nil)
+ ((eq (car b) old-buffer) t)
+ (t (< (length (memq (car a) next-buffers))
+ (length (memq (car b) next-buffers))))))))
+ (set-window-prev-buffers window prev-buffers)
+ ;; When record-window-buffer doesn't reset next-buffers.
+ (set-window-next-buffers window nil)))))
;; Remove killed buffers from WINDOW's previous and next buffers.
(when killed-buffers
@@ -4812,7 +4853,7 @@ switch-to-next-buffer
((or switch-to-prev-buffer-skip
(not switch-to-visible-buffer))
frame)))
- new-buffer entry killed-buffers skipped)
+ new-buffer entry killed-buffers skipped wrapped)
(when (window-minibuffer-p window)
;; Don't switch in minibuffer window.
(unless (setq window (minibuffer-selected-window))
@@ -4839,7 +4880,7 @@ switch-to-next-buffer
(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
+ (unless (or window-side switch-to-prev-buffer-wrap)
(dolist (buffer (buffer-list frame))
(when (and (buffer-live-p buffer)
(not (eq buffer old-buffer))
@@ -4856,27 +4897,38 @@ switch-to-next-buffer
(throw 'found t)))))
;; Scan WINDOW's reverted previous buffers last (must not use
;; nreverse here!)
- (dolist (entry (reverse (window-prev-buffers window)))
- (when (and (not (eq new-buffer (car entry)))
- (not (eq old-buffer (car entry)))
- (setq new-buffer (car entry))
- (or (buffer-live-p new-buffer)
- (not (setq killed-buffers
- (cons new-buffer killed-buffers))))
- (or (null pred) (funcall pred 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))))
+ (if (eq switch-to-prev-buffer-wrap 'stop)
+ (setq wrapped 'stop)
+ (dolist (entry (reverse (window-prev-buffers window)))
+ (when (and (not (eq new-buffer (car entry)))
+ (not (eq old-buffer (car entry)))
+ (setq new-buffer (car entry))
+ (or (buffer-live-p new-buffer)
+ (not (setq killed-buffers
+ (cons new-buffer killed-buffers))))
+ (or (null pred) (funcall pred new-buffer)))
+ (if (switch-to-prev-buffer-skip-p skip window new-buffer)
+ (setq skipped (or skipped new-buffer))
+ (setq wrapped t)
+ (set-window-buffer-start-and-point
+ window new-buffer (nth 1 entry) (nth 2 entry))
+ (throw 'found t)))))
- (when (and skipped (not (functionp switch-to-prev-buffer-skip)))
+ (when (and skipped (not (functionp switch-to-prev-buffer-skip))
+ (not wrapped))
;; Show first skipped buffer, unless skip was a function.
(setq new-buffer skipped)
(set-window-buffer-start-and-point window new-buffer)))
- ;; Remove `new-buffer' from and restore WINDOW's next buffers.
- (set-window-next-buffers window (delq new-buffer next-buffers))
+ (if (not (and switch-to-prev-buffer-wrap wrapped))
+ ;; Remove `new-buffer' from and restore WINDOW's next buffers.
+ (set-window-next-buffers window (delq new-buffer next-buffers))
+ (if (eq wrapped 'stop)
+ (setq new-buffer nil)
+ (let ((prev-buffers (window-prev-buffers window)))
+ (setq prev-buffers
+ (nreverse (delq new-buffer (mapcar #'car prev-buffers))))
+ (set-window-next-buffers window prev-buffers))))
;; Remove killed buffers from WINDOW's previous and next buffers.
(when killed-buffers
- bug#69993: Wrap window buffers while cycling, Juri Linkov, 2024/03/25
- bug#69993: Wrap window buffers while cycling, martin rudalics, 2024/03/25
- bug#69993: Wrap window buffers while cycling, Juri Linkov, 2024/03/25
- bug#69993: Wrap window buffers while cycling, martin rudalics, 2024/03/26
- bug#69993: Wrap window buffers while cycling, Juri Linkov, 2024/03/27
- bug#69993: Wrap window buffers while cycling, martin rudalics, 2024/03/27
- bug#69993: Wrap window buffers while cycling,
Juri Linkov <=
- bug#69993: Wrap window buffers while cycling, martin rudalics, 2024/03/28
- bug#69993: Wrap window buffers while cycling, Juri Linkov, 2024/03/28
- bug#69993: Wrap window buffers while cycling, martin rudalics, 2024/03/29
- bug#69993: Wrap window buffers while cycling, Juri Linkov, 2024/03/29
- bug#69993: Wrap window buffers while cycling, martin rudalics, 2024/03/30
- bug#69993: Wrap window buffers while cycling, Juri Linkov, 2024/03/30
- bug#69993: Wrap window buffers while cycling, martin rudalics, 2024/03/31