unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#70949: display-buffer-choose-some-window
@ 2024-05-14 16:56 Juri Linkov
  2024-05-15  8:06 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 37+ messages in thread
From: Juri Linkov @ 2024-05-14 16:56 UTC (permalink / raw)
  To: 70949; +Cc: martin rudalics

[-- Attachment #1: Type: text/plain, Size: 955 bytes --]

Addressing the request in help-gnu-emacs quoted below:

>> When cycling through, say, a rgrep result buffer with n
>> (next-error-no-select) and p (previous-error-no-select), file results
>> are displayed in every open window, with the exception of the window
>> containing the rgrep results themselves.
>>
>> I'd rather have file results remain in just one window so that I can use
>> other buffers while still viewing search results. Is this possible?
>>
>> How would I go about this? Are there any better options?
>
> The problem is that the first thing that
> 'display-buffer-use-some-window' tries to do
> is to find the least recently used window
> with 'display-buffer--lru-window'.
>
> I think this behavior should be customizable with a new option,
> so that you could prefer always to use
> the most recently used window.

here is a patch that adds such option that allows to customize
what window display-buffer-use-some-window should prefer:


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: display-buffer-choose-some-window.patch --]
[-- Type: text/x-diff, Size: 2280 bytes --]

diff --git a/lisp/window.el b/lisp/window.el
index 8feeba0d83e..d34e369167e 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -8721,6 +8726,22 @@ display-buffer--lru-window
 	      (setq best-window window))))))
     (or best-window second-best-window)))
 
+(defcustom display-buffer-choose-some-window 'lru
+  "How to choose an existing window.
+This defines a strategy of choosing some window
+by `display-buffer-use-some-window'.
+
+The possible choices are `lru' (the default) to select the least recently
+used window on that frame, and `mru' to select the most recently used
+window on that frame.  When a function, it takes two arguments: a buffer
+and an alist, and should return the window where to display the buffer."
+  :type '(choice (const :tag "Least recently used" lru)
+                 (const :tag "Most recently used" mru)
+                 (function :tag "Custom function"))
+  :group 'windows
+  :group 'frames
+  :version "30.1")
+
 (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
@@ -8743,11 +8764,17 @@ display-buffer-use-some-window
 		    (window--frame-usable-p (last-nonminibuffer-frame))))
 	 (window
 	  ;; Reuse an existing window.
-	  (or (display-buffer--lru-window
-               ;; If ALIST specifies 'lru-frames' or 'window-min-width'
-               ;; let them prevail.
-               (append alist `((lru-frames . ,frame)
-                               (window-min-width . full-width))))
+	  (or (cond
+               ((eq display-buffer-choose-some-window 'lru)
+                (display-buffer--lru-window
+                 ;; If ALIST specifies 'lru-frames' or 'window-min-width'
+                 ;; let them prevail.
+                 (append alist `((lru-frames . ,frame)
+                                 (window-min-width . full-width)))))
+               ((eq display-buffer-choose-some-window 'mru)
+                (get-mru-window nil nil t))
+               ((functionp display-buffer-choose-some-window)
+                (funcall display-buffer-choose-some-window buffer alist)))
 	      (let ((window (get-buffer-window buffer 'visible)))
 		(unless (and not-this-window
 			     (eq window (selected-window)))

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* bug#70949: display-buffer-choose-some-window
  2024-05-14 16:56 bug#70949: display-buffer-choose-some-window Juri Linkov
@ 2024-05-15  8:06 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2024-05-15 16:49   ` Juri Linkov
  0 siblings, 1 reply; 37+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-05-15  8:06 UTC (permalink / raw)
  To: Juri Linkov, 70949

 > +(defcustom display-buffer-choose-some-window 'lru
 > +  "How to choose an existing window.
 > +This defines a strategy of choosing some window
 > +by `display-buffer-use-some-window'.
 > +
 > +The possible choices are `lru' (the default) to select the least recently
 > +used window on that frame, and `mru' to select the most recently used
 > +window on that frame.  When a function, it takes two arguments: a buffer
 > +and an alist, and should return the window where to display the buffer."

I'd call the option 'display-buffer-use-some-window-method' so it's more
clear that it pertains to 'display-buffer-use-some-window'.  As for the
first line of the doc-string I'd write

"Which window `display-buffer-use-some-window' should choose."

Also, we should mention the constraints used for 'lru' and that 'mru'
avoids the selected window here.

martin





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#70949: display-buffer-choose-some-window
  2024-05-15  8:06 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2024-05-15 16:49   ` Juri Linkov
  2024-05-16  8:20     ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 37+ messages in thread
From: Juri Linkov @ 2024-05-15 16:49 UTC (permalink / raw)
  To: martin rudalics; +Cc: 70949

[-- Attachment #1: Type: text/plain, Size: 1027 bytes --]

>> +(defcustom display-buffer-choose-some-window 'lru
>> +  "How to choose an existing window.
>> +This defines a strategy of choosing some window
>> +by `display-buffer-use-some-window'.
>> +
>> +The possible choices are `lru' (the default) to select the least recently
>> +used window on that frame, and `mru' to select the most recently used
>> +window on that frame.  When a function, it takes two arguments: a buffer
>> +and an alist, and should return the window where to display the buffer."
>
> I'd call the option 'display-buffer-use-some-window-method' so it's more
> clear that it pertains to 'display-buffer-use-some-window'.  As for the
> first line of the doc-string I'd write
>
> "Which window `display-buffer-use-some-window' should choose."

Ok, done in this patch.

> Also, we should mention the constraints used for 'lru' and that 'mru'
> avoids the selected window here.

Sorry, I don't understand what constraints.  The docstring of
'display-buffer-use-some-window' doesn't mention any 'lru' constraints.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: display-buffer-use-some-window-method.patch --]
[-- Type: text/x-diff, Size: 2253 bytes --]

diff --git a/lisp/window.el b/lisp/window.el
index 3935908fdb4..01c8429500d 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -8726,6 +8726,20 @@ display-buffer--lru-window
 	      (setq best-window window))))))
     (or best-window second-best-window)))
 
+(defcustom display-buffer-use-some-window-method 'lru
+  "Which window `display-buffer-use-some-window' should choose.
+The possible choices are `lru' (the default) to select the least
+recently used window, and `mru' to select the most recently used
+window (not taking into account the selected window).  When a function,
+it takes two arguments: a buffer and an alist, and should return the
+window where to display the buffer."
+  :type '(choice (const :tag "Least recently used" lru)
+                 (const :tag "Most recently used" mru)
+                 (function :tag "Custom function"))
+  :group 'windows
+  :group 'frames
+  :version "30.1")
+
 (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
@@ -8748,11 +8762,17 @@ display-buffer-use-some-window
 		    (window--frame-usable-p (last-nonminibuffer-frame))))
 	 (window
 	  ;; Reuse an existing window.
-	  (or (display-buffer--lru-window
-               ;; If ALIST specifies 'lru-frames' or 'window-min-width'
-               ;; let them prevail.
-               (append alist `((lru-frames . ,frame)
-                               (window-min-width . full-width))))
+	  (or (cond
+               ((eq display-buffer-use-some-window-method 'lru)
+                (display-buffer--lru-window
+                 ;; If ALIST specifies 'lru-frames' or 'window-min-width'
+                 ;; let them prevail.
+                 (append alist `((lru-frames . ,frame)
+                                 (window-min-width . full-width)))))
+               ((eq display-buffer-use-some-window-method 'mru)
+                (get-mru-window t t t))
+               ((functionp display-buffer-use-some-window-method)
+                (funcall display-buffer-use-some-window-method buffer alist)))
 	      (let ((window (get-buffer-window buffer 'visible)))
 		(unless (and not-this-window
 			     (eq window (selected-window)))

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* bug#70949: display-buffer-choose-some-window
  2024-05-15 16:49   ` Juri Linkov
@ 2024-05-16  8:20     ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2024-05-17  6:40       ` Juri Linkov
  0 siblings, 1 reply; 37+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-05-16  8:20 UTC (permalink / raw)
  To: Juri Linkov; +Cc: 70949

 >> Also, we should mention the constraints used for 'lru' and that 'mru'
 >> avoids the selected window here.
 >
 > Sorry, I don't understand what constraints.  The docstring of
 > 'display-buffer-use-some-window' doesn't mention any 'lru' constraints.

For historical reasons, 'display-buffer-use-some-window' avoids windows
that are not full-width and windows on another frame via

                (append alist `((lru-frames . ,frame)
                                (window-min-width . full-width))))

The default behavior can be overridden with appropriate alist entries
which are not mentioned in the doc-string but are described in the Elisp
manual.  Your option should mention them because they defy a "strict"
interpretation of 'lru'.

BTW, you could have, instead of an option, provided a 'some-window'
alist entry with the possible values 'lru', 'mru' or a function.  Why
did you prefer the option?

martin





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#70949: display-buffer-choose-some-window
  2024-05-16  8:20     ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2024-05-17  6:40       ` Juri Linkov
  2024-05-18  9:21         ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 37+ messages in thread
From: Juri Linkov @ 2024-05-17  6:40 UTC (permalink / raw)
  To: martin rudalics; +Cc: 70949

[-- Attachment #1: Type: text/plain, Size: 1289 bytes --]

>>> Also, we should mention the constraints used for 'lru' and that 'mru'
>>> avoids the selected window here.
>>
>> Sorry, I don't understand what constraints.  The docstring of
>> 'display-buffer-use-some-window' doesn't mention any 'lru' constraints.
>
> For historical reasons, 'display-buffer-use-some-window' avoids windows
> that are not full-width and windows on another frame via
>
>                (append alist `((lru-frames . ,frame)
>                                (window-min-width . full-width))))
>
> The default behavior can be overridden with appropriate alist entries
> which are not mentioned in the doc-string but are described in the Elisp
> manual.  Your option should mention them because they defy a "strict"
> interpretation of 'lru'.

Thanks for explanations, now these constraints are documented.

> BTW, you could have, instead of an option, provided a 'some-window'
> alist entry with the possible values 'lru', 'mru' or a function.  Why
> did you prefer the option?

I already considered adding an alist entry, but the problem is that
it's not clear where users would put it to cover display of all buffers.
But I could reconsider such solution, if you will suggest a suitable place
for users to add such an alist like (some-window . mru) for all buffers.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: display-buffer-use-some-window-method.patch --]
[-- Type: text/x-diff, Size: 2426 bytes --]

diff --git a/lisp/window.el b/lisp/window.el
index 8feeba0d83e..67af4753a70 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -8721,6 +8726,24 @@ display-buffer--lru-window
 	      (setq best-window window))))))
     (or best-window second-best-window)))
 
+(defcustom display-buffer-use-some-window-method 'lru
+  "Which window `display-buffer-use-some-window' should choose.
+The possible choices are `lru' (the default) to select the least
+recently used window, and `mru' to select the most recently used
+window .  When a function, it takes two arguments: a buffer and
+an alist, and should return the window where to display the buffer.
+
+When the value is `lru', it avoids selecting windows that are
+not full-width and windows on another frame.
+When the value is `mru', it avoids selecting an already selected window
+and windows on another frame."
+  :type '(choice (const :tag "Least recently used" lru)
+                 (const :tag "Most recently used" mru)
+                 (function :tag "Custom function"))
+  :group 'windows
+  :group 'frames
+  :version "30.1")
+
 (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
@@ -8743,11 +8767,17 @@ display-buffer-use-some-window
 		    (window--frame-usable-p (last-nonminibuffer-frame))))
 	 (window
 	  ;; Reuse an existing window.
-	  (or (display-buffer--lru-window
-               ;; If ALIST specifies 'lru-frames' or 'window-min-width'
-               ;; let them prevail.
-               (append alist `((lru-frames . ,frame)
-                               (window-min-width . full-width))))
+	  (or (cond
+               ((eq display-buffer-use-some-window-method 'lru)
+                (display-buffer--lru-window
+                 ;; If ALIST specifies 'lru-frames' or 'window-min-width'
+                 ;; let them prevail.
+                 (append alist `((lru-frames . ,frame)
+                                 (window-min-width . full-width)))))
+               ((eq display-buffer-use-some-window-method 'mru)
+                (get-mru-window nil nil t))
+               ((functionp display-buffer-use-some-window-method)
+                (funcall display-buffer-use-some-window-method buffer alist)))
 	      (let ((window (get-buffer-window buffer 'visible)))
 		(unless (and not-this-window
 			     (eq window (selected-window)))

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* bug#70949: display-buffer-choose-some-window
  2024-05-17  6:40       ` Juri Linkov
@ 2024-05-18  9:21         ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2024-05-20  6:15           ` Juri Linkov
  0 siblings, 1 reply; 37+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-05-18  9:21 UTC (permalink / raw)
  To: Juri Linkov; +Cc: 70949

 > I already considered adding an alist entry, but the problem is that
 > it's not clear where users would put it to cover display of all buffers.
 > But I could reconsider such solution, if you will suggest a suitable place
 > for users to add such an alist like (some-window . mru) for all buffers.

Why would that be a problem?  Any "(some-window . mru)" entry would
exclusively affect the execution of 'display-buffer-use-some-window'.
So what would be wrong with

(customize-set-variable
  'display-buffer-alist
  (cons '(".*" nil (some-window . mru)) display-buffer-alist))

martin





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#70949: display-buffer-choose-some-window
  2024-05-18  9:21         ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2024-05-20  6:15           ` Juri Linkov
  2024-05-20  8:01             ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 37+ messages in thread
From: Juri Linkov @ 2024-05-20  6:15 UTC (permalink / raw)
  To: martin rudalics; +Cc: 70949

[-- Attachment #1: Type: text/plain, Size: 755 bytes --]

>> I already considered adding an alist entry, but the problem is that
>> it's not clear where users would put it to cover display of all buffers.
>> But I could reconsider such solution, if you will suggest a suitable place
>> for users to add such an alist like (some-window . mru) for all buffers.
>
> Why would that be a problem?  Any "(some-window . mru)" entry would
> exclusively affect the execution of 'display-buffer-use-some-window'.
> So what would be wrong with
>
> (customize-set-variable
>  'display-buffer-alist
>  (cons '(".*" nil (some-window . mru)) display-buffer-alist))

Or maybe users could customize base-action:

  (setq display-buffer-base-action '(nil . ((some-window . mru))))

Ok, here is a new patch with a new alist entry:


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: some-window-method.patch --]
[-- Type: text/x-diff, Size: 2578 bytes --]

diff --git a/lisp/window.el b/lisp/window.el
index 8feeba0d83e..5f9dec1dc25 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -7851,7 +7856,16 @@ display-buffer
     and `preserve-size' are applied.  The function is supposed
     to fill the window body with some contents that might depend
     on dimensions of the displayed window.
- `post-command-select-window' -- A non-nil value means that after the
+ `some-window' -- This entry defines which window
+    `display-buffer-use-some-window' should choose.  The possible choices
+    are `lru' or nil (the default) to select the least recently used window,
+    and `mru' to select the most recently used window .  When a function, it
+    takes two arguments: a buffer and an alist, and should return the window
+    where to display the buffer.  When the value is `lru', it avoids
+    selecting windows that are not full-width and windows on another frame.
+    When the value is `mru', it avoids selecting an already selected window
+    and windows on another frame.
+  `post-command-select-window' -- A non-nil value means that after the
     current command is executed and the hook `post-command-hook' is called,
     the window displayed by this function will be selected.  A nil value
     means that if functions like `pop-to-buffer' selected another window,
@@ -8739,15 +8753,22 @@ display-buffer-use-some-window
 called only by `display-buffer' or a function directly or
 indirectly called by the latter."
   (let* ((not-this-window (cdr (assq 'inhibit-same-window alist)))
+	 (some-window-method (cdr (assq 'some-window alist)))
 	 (frame (or (window--frame-usable-p (selected-frame))
 		    (window--frame-usable-p (last-nonminibuffer-frame))))
 	 (window
 	  ;; Reuse an existing window.
-	  (or (display-buffer--lru-window
-               ;; If ALIST specifies 'lru-frames' or 'window-min-width'
-               ;; let them prevail.
-               (append alist `((lru-frames . ,frame)
-                               (window-min-width . full-width))))
+	  (or (cond
+	       ((memq some-window-method '(nil lru))
+		(display-buffer--lru-window
+		 ;; If ALIST specifies 'lru-frames' or 'window-min-width'
+		 ;; let them prevail.
+		 (append alist `((lru-frames . ,frame)
+				 (window-min-width . full-width)))))
+	       ((eq some-window-method 'mru)
+		(get-mru-window nil nil t))
+	       ((functionp some-window-method)
+		(funcall some-window-method buffer alist)))
 	      (let ((window (get-buffer-window buffer 'visible)))
 		(unless (and not-this-window
 			     (eq window (selected-window)))

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* bug#70949: display-buffer-choose-some-window
  2024-05-20  6:15           ` Juri Linkov
@ 2024-05-20  8:01             ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2024-05-20 16:54               ` Juri Linkov
  0 siblings, 1 reply; 37+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-05-20  8:01 UTC (permalink / raw)
  To: Juri Linkov; +Cc: 70949

 > +    `display-buffer-use-some-window' should choose.  The possible choices
 > +    are `lru' or nil (the default) to select the least recently used window,
 > +    and `mru' to select the most recently used window .  When a function, it

I'd say "It can also be a function that takes two arguments ..."

 > +    takes two arguments: a buffer and an alist, and should return the window
 > +    where to display the buffer.  When the value is `lru', it avoids
 > +    selecting windows that are not full-width and windows on another frame.
 > +    When the value is `mru', it avoids selecting an already selected window
 > +    and windows on another frame.

I'd say "..., it does not consider the selected window and windows on
any frame but the selected one."

But the more important thing is to tell users how this can help to fix
problems like the one that triggered this thread.  A short description
in the doc-string and a more elaborated one with an example in the Elisp
manual in the description of 'display-buffer-use-some-window' and in the
"Action Alists for Buffer Display" section.

martin





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#70949: display-buffer-choose-some-window
  2024-05-20  8:01             ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2024-05-20 16:54               ` Juri Linkov
  2024-05-21  8:21                 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 37+ messages in thread
From: Juri Linkov @ 2024-05-20 16:54 UTC (permalink / raw)
  To: martin rudalics; +Cc: 70949

[-- Attachment #1: Type: text/plain, Size: 1168 bytes --]

>> +    `display-buffer-use-some-window' should choose.  The possible choices
>> +    are `lru' or nil (the default) to select the least recently used window,
>> +    and `mru' to select the most recently used window .  When a function, it
>
> I'd say "It can also be a function that takes two arguments ..."
>
>> +    takes two arguments: a buffer and an alist, and should return the window
>> +    where to display the buffer.  When the value is `lru', it avoids
>> +    selecting windows that are not full-width and windows on another frame.
>> +    When the value is `mru', it avoids selecting an already selected window
>> +    and windows on another frame.
>
> I'd say "..., it does not consider the selected window and windows on
> any frame but the selected one."
>
> But the more important thing is to tell users how this can help to fix
> problems like the one that triggered this thread.  A short description
> in the doc-string and a more elaborated one with an example in the Elisp
> manual in the description of 'display-buffer-use-some-window' and in the
> "Action Alists for Buffer Display" section.

Thanks for suggestions, here is a complete patch:


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: some-window.patch --]
[-- Type: text/x-diff, Size: 5632 bytes --]

diff --git a/doc/lispref/windows.texi b/doc/lispref/windows.texi
index 61e72eae680..efffb0d3f3f 100644
--- a/doc/lispref/windows.texi
+++ b/doc/lispref/windows.texi
@@ -2805,6 +2805,14 @@ Buffer Display Action Functions
 some other window, preferably a large window on some visible frame.  It
 can fail if all windows are dedicated to other buffers (@pxref{Dedicated
 Windows}).
+
+The above describes the behavior when @code{some-window} @var{alist}
+entry is @code{lru} or @code{nil} which is the default.  But when,
+for example, @code{display-buffer-base-action} is customized to
+@w{@code{(nil . ((some-window . mru)))}}, then the value @code{mru}
+means that this function will prefer the most recently used window
+that is useful to display several buffers in the same window
+in a layout with more than two windows.
 @end defun
 
 @defun display-buffer-use-least-recent-window buffer alist
@@ -3358,6 +3366,16 @@ Buffer Display Action Alists
 will display the buffer.  @code{display-buffer-no-window} is the only
 action function that cares about this entry.
 
+@vindex some-window@r{, a buffer display action alist entry}
+@item some-window
+If the value is @code{nil} or @code{lru}, @code{display-buffer-use-some-window}
+prefers the least recently used window while avoiding selecting windows
+that are not full-width and windows on another frame.  If the value is
+@code{mru}, it prefers the most recently used window not considering the
+selected window and windows on any frame but the selected one.  If the
+value is a function, it is called with two arguments: a buffer and an
+alist, and should return the window where to display the buffer.
+
 @vindex body-function@r{, a buffer display action alist entry}
 @item body-function
 The value must be a function taking one argument (a displayed window).
diff --git a/etc/NEWS b/etc/NEWS
index 4e52d4dccb2..cc2405ca09a 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -306,6 +306,14 @@ right-aligned to is controlled by the new user option
 
 ** Windows
 
++++
+*** New action alist entry 'some-window' for 'display-buffer'.
+It defines which window 'display-buffer-use-some-window' should prefer.
+For example, when 'display-buffer-base-action' is customized to
+'(nil . ((some-window . mru)))' then any buffer will be displayed
+in the same most recently used window on a layout with more
+than two windows.
+
 +++
 *** New action alist entry 'category' for 'display-buffer'.
 If the caller of 'display-buffer' passes '(category . symbol)'
diff --git a/lisp/window.el b/lisp/window.el
index e709e978cc9..1549fba6f2e 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -7845,6 +7850,18 @@ display-buffer
     parameters to give the chosen window.
  `allow-no-window' -- A non-nil value means that `display-buffer'
     may not display the buffer and return nil immediately.
+ `some-window' -- This entry defines which window
+    `display-buffer-use-some-window' should choose.  The possible choices
+    are `lru' or nil (the default) to select the least recently used window,
+    and `mru' to select the most recently used window.  It can also be
+    a function that takes two arguments: a buffer and an alist, and should
+    return the window where to display the buffer.  If the value is `lru',
+    it avoids selecting windows that are not full-width and windows on
+    another frame.  If the value is `mru', it does not consider the
+    selected window and windows on any frame but the selected one.
+    It's useful to customize `display-buffer-base-action' to
+    `(nil . ((some-window . mru))) when you want to display buffers in
+    the same non-selected window in a layout with more than two windows.
  `body-function' -- A function called with one argument - the
     displayed window.  It is called after the buffer is
     displayed, and before `window-height', `window-width'
@@ -8734,20 +8751,33 @@ display-buffer-use-some-window
 event that a window on another frame is chosen, avoid raising
 that frame.
 
+If ALIST contains a non-nil `some-window' entry, then prefer the least
+recently used window if the entry's value is `lru' or nil, or the most
+recently used window if it's `mru'.  If the value is a function, it is
+called with two arguments: a buffer and an alist, and should return
+the window where to display the buffer.
+
 This is an action function for buffer display, see Info
 node `(elisp) Buffer Display Action Functions'.  It should be
 called only by `display-buffer' or a function directly or
 indirectly called by the latter."
   (let* ((not-this-window (cdr (assq 'inhibit-same-window alist)))
+	 (some-window-method (cdr (assq 'some-window alist)))
 	 (frame (or (window--frame-usable-p (selected-frame))
 		    (window--frame-usable-p (last-nonminibuffer-frame))))
 	 (window
 	  ;; Reuse an existing window.
-	  (or (display-buffer--lru-window
-               ;; If ALIST specifies 'lru-frames' or 'window-min-width'
-               ;; let them prevail.
-               (append alist `((lru-frames . ,frame)
-                               (window-min-width . full-width))))
+	  (or (cond
+	       ((memq some-window-method '(nil lru))
+		(display-buffer--lru-window
+		 ;; If ALIST specifies 'lru-frames' or 'window-min-width'
+		 ;; let them prevail.
+		 (append alist `((lru-frames . ,frame)
+				 (window-min-width . full-width)))))
+	       ((eq some-window-method 'mru)
+		(get-mru-window nil nil t))
+	       ((functionp some-window-method)
+		(funcall some-window-method buffer alist)))
 	      (let ((window (get-buffer-window buffer 'visible)))
 		(unless (and not-this-window
 			     (eq window (selected-window)))

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* bug#70949: display-buffer-choose-some-window
  2024-05-20 16:54               ` Juri Linkov
@ 2024-05-21  8:21                 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2024-05-21 17:18                   ` Juri Linkov
  0 siblings, 1 reply; 37+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-05-21  8:21 UTC (permalink / raw)
  To: Juri Linkov; +Cc: 70949

+The above describes the behavior when @code{some-window} @var{alist}
+entry is @code{lru} or @code{nil} which is the default.  But when,
+for example, @code{display-buffer-base-action} is customized to
+@w{@code{(nil . ((some-window . mru)))}}, then the value @code{mru}
+means that this function will prefer the most recently used window
+that is useful to display several buffers in the same window
+in a layout with more than two windows.

This is ambiguous - we should emphasize that these buffers are not
displayed at the same time.  I'd write something like the following:

   The default behavior might become irritating when 'display-buffer' is
   used to display a number of related buffers in a row.

   Consider a configuration of two or more windows where a user wants to
   consult, in a non-selected window, one after the other, the results of a
   query spread among several buffers.  With the 'lru' strategy, Emacs
   might continuously choose another window because the least recently used
   window changes with every call of 'display-buffer-use-some-window'.
   With the 'mru' strategy, the window chosen would always remain the same,
   resulting in a less confusing user experience.

If I got it right ...

martin





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#70949: display-buffer-choose-some-window
  2024-05-21  8:21                 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2024-05-21 17:18                   ` Juri Linkov
  2024-05-22  7:39                     ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 37+ messages in thread
From: Juri Linkov @ 2024-05-21 17:18 UTC (permalink / raw)
  To: martin rudalics; +Cc: 70949

> +The above describes the behavior when @code{some-window} @var{alist}
> +entry is @code{lru} or @code{nil} which is the default.  But when,
> +for example, @code{display-buffer-base-action} is customized to
> +@w{@code{(nil . ((some-window . mru)))}}, then the value @code{mru}
> +means that this function will prefer the most recently used window
> +that is useful to display several buffers in the same window
> +in a layout with more than two windows.
>
> This is ambiguous - we should emphasize that these buffers are not
> displayed at the same time.  I'd write something like the following:
>
>   The default behavior might become irritating when 'display-buffer' is
>   used to display a number of related buffers in a row.
>
>   Consider a configuration of two or more windows where a user wants to
>   consult, in a non-selected window, one after the other, the results of a
>   query spread among several buffers.  With the 'lru' strategy, Emacs
>   might continuously choose another window because the least recently used
>   window changes with every call of 'display-buffer-use-some-window'.
>   With the 'mru' strategy, the window chosen would always remain the same,
>   resulting in a less confusing user experience.
>
> If I got it right ...

Not quite right.  It's not about a less confusing user experience.
Here is what the OP wrote for this request:

    I'd rather have file results remain in just one window so that I can use
    other buffers while still viewing search results.

Probably here would be better to say not "other buffers", but "other windows".





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#70949: display-buffer-choose-some-window
  2024-05-21 17:18                   ` Juri Linkov
@ 2024-05-22  7:39                     ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2024-05-23  6:16                       ` Juri Linkov
  0 siblings, 1 reply; 37+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-05-22  7:39 UTC (permalink / raw)
  To: Juri Linkov; +Cc: 70949

 > Not quite right.  It's not about a less confusing user experience.
 > Here is what the OP wrote for this request:
 >
 >      I'd rather have file results remain in just one window so that I can use
 >      other buffers while still viewing search results.
 >
 > Probably here would be better to say not "other buffers", but "other windows".

Then we have a problem.  If the OP wants to "use other windows" (and not
just a single other window), the 'mru' will become one of these other
windows and not the last one used by 'display-buffer-use-some-window'.
I think the OP should use a side window to show "file results" which
would support the "remain in just one window" paradigm out of the box.

martin





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#70949: display-buffer-choose-some-window
  2024-05-22  7:39                     ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2024-05-23  6:16                       ` Juri Linkov
  2024-05-23  7:22                         ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 37+ messages in thread
From: Juri Linkov @ 2024-05-23  6:16 UTC (permalink / raw)
  To: martin rudalics; +Cc: 70949

>> Not quite right.  It's not about a less confusing user experience.
>> Here is what the OP wrote for this request:
>>
>>      I'd rather have file results remain in just one window so that I can use
>>      other buffers while still viewing search results.
>>
>> Probably here would be better to say not "other buffers", but "other windows".
>
> Then we have a problem.  If the OP wants to "use other windows" (and not
> just a single other window), the 'mru' will become one of these other
> windows and not the last one used by 'display-buffer-use-some-window'.

With 'mru' the window used by 'display-buffer-use-some-window'
is the last one.  Here is the use case of the OP:

    When cycling through, say, a rgrep result buffer with n
    (next-error-no-select) and p (previous-error-no-select), file results
    are displayed in every open window, with the exception of the window
    containing the rgrep results themselves.
    I'd rather have file results remain in just one window
    so that I can use other buffers while still viewing search results.

> I think the OP should use a side window to show "file results" which
> would support the "remain in just one window" paradigm out of the box.

Unfortunately, a side window is not a solution since after finishing
navigating the search results, the window should remain normal.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#70949: display-buffer-choose-some-window
  2024-05-23  6:16                       ` Juri Linkov
@ 2024-05-23  7:22                         ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2024-05-23 17:27                           ` Juri Linkov
  0 siblings, 1 reply; 37+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-05-23  7:22 UTC (permalink / raw)
  To: Juri Linkov; +Cc: 70949

 > With 'mru' the window used by 'display-buffer-use-some-window'
 > is the last one.  Here is the use case of the OP:
 >
 >      When cycling through, say, a rgrep result buffer with n
 >      (next-error-no-select) and p (previous-error-no-select), file results
 >      are displayed in every open window, with the exception of the window
 >      containing the rgrep results themselves.

That's the problem I tried to address in my first proposal: Displaying a
file in "every open window" can be confusing so we want to use always
the same non-selected window ...

 >      I'd rather have file results remain in just one window
 >      so that I can use other buffers while still viewing search results.

... but if, as you said earlier, the OP means "other windows" here, the
resulting behavior becomes unpredictable again because the 'mru' window
will change to the last "other" window of the user.

 >> I think the OP should use a side window to show "file results" which
 >> would support the "remain in just one window" paradigm out of the box.
 >
 > Unfortunately, a side window is not a solution since after finishing
 > navigating the search results, the window should remain normal.

Then maybe a separate category for rgrep buffers could help here.

martin





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#70949: display-buffer-choose-some-window
  2024-05-23  7:22                         ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2024-05-23 17:27                           ` Juri Linkov
  2024-05-24  9:32                             ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 37+ messages in thread
From: Juri Linkov @ 2024-05-23 17:27 UTC (permalink / raw)
  To: martin rudalics; +Cc: 70949

>> With 'mru' the window used by 'display-buffer-use-some-window'
>> is the last one.  Here is the use case of the OP:
>>
>>      When cycling through, say, a rgrep result buffer with n
>>      (next-error-no-select) and p (previous-error-no-select), file results
>>      are displayed in every open window, with the exception of the window
>>      containing the rgrep results themselves.
>
> That's the problem I tried to address in my first proposal: Displaying a
> file in "every open window" can be confusing so we want to use always
> the same non-selected window ...

And I tried to address exactly the same problem.  I only disagreed with
using the word "confusing".  I think this is rather about convenience.

>>      I'd rather have file results remain in just one window
>>      so that I can use other buffers while still viewing search results.
>
> ... but if, as you said earlier, the OP means "other windows" here, the
> resulting behavior becomes unpredictable again because the 'mru' window
> will change to the last "other" window of the user.

This makes the behavior more predictable: the user will know that all
buffers will be displayed in the most recently used window, so the user
can switch to that window before continuing to navigate buffers.

>>> I think the OP should use a side window to show "file results" which
>>> would support the "remain in just one window" paradigm out of the box.
>>
>> Unfortunately, a side window is not a solution since after finishing
>> navigating the search results, the window should remain normal.
>
> Then maybe a separate category for rgrep buffers could help here.

This is not about rgrep buffers.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#70949: display-buffer-choose-some-window
  2024-05-23 17:27                           ` Juri Linkov
@ 2024-05-24  9:32                             ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2024-05-24 17:38                               ` Juri Linkov
  0 siblings, 1 reply; 37+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-05-24  9:32 UTC (permalink / raw)
  To: Juri Linkov; +Cc: 70949

 > And I tried to address exactly the same problem.  I only disagreed with
 > using the word "confusing".  I think this is rather about convenience.

Then I won't insist.

 > This makes the behavior more predictable: the user will know that all
 > buffers will be displayed in the most recently used window, so the user
 > can switch to that window before continuing to navigate buffers.

Not really.  The window switched to becomes the selected window and the
'mru' window used will be the window where the user was working before
the switch due to NOT-SELECTED being t.

 >> Then maybe a separate category for rgrep buffers could help here.
 >
 > This is not about rgrep buffers.

Consider the completely untested action function below supposed to be
called with a (related-window . rgrep) alist argument.

martin

(defun display-buffer-in-related-window (buffer alist)
   "Display BUFFER in a related window.
ALIST is an association list of action symbols and values.  See
Info node `(elisp) Buffer Display Action Alists' for details of
such alists.

If ALIST has a non-nil `inhibit-same-window' entry, the selected
window is not usable.  A dedicated window is usable only if it
already shows BUFFER.  If ALIST contains a `related-window'
entry, the window specified by that entry (either a variable
or a value) is usable even if it never showed BUFFER before.

If ALIST contains a `reusable-frames' entry, its value determines
which frames to search for a usable 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 more than one window is usable according to these rules,
apply the following order of preference:

- Use the window specified by any `related-window' ALIST entry,
   provided it is not the selected window.

- Use a window that showed BUFFER before, provided it is not the
   selected window.

- Use the selected window if it is either specified by a
   `related-window' ALIST entry or showed BUFFER before.

This is an action function for buffer display, see Info
node `(elisp) Buffer Display Action Functions'.  It should be
called only by `display-buffer' or a function directly or
indirectly called by the latter."
   (let* ((alist-entry (assq 'reusable-frames alist))
	 (inhibit-same-window
	  (cdr (assq 'inhibit-same-window alist)))
	 (frames (cond
		  (alist-entry (cdr alist-entry))
		  ((window--pop-up-frames alist)
		   0)
		  (display-buffer-reuse-frames 0)
		  (t (last-nonminibuffer-frame))))
	 (first (and (frame-live-p frames) (frame-first-window frames)))
          (related-window (cdr (assq 'related-window alist)))
	 best-window second-best-window window)
     ;; Scan windows whether they have a matching 'related-window'
     ;; parameter.
     (catch 'best
       (dolist (window (window-list-1 first 'nomini frames))
	(when (and (eq (window-parameter window 'related-window)
		       related-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 `related-window' entry, that entry may override
     ;; anything we found so far.
     (when (and related-window (symbolp related-window)
                (boundp related-window))
       (setq related-window (symbol-value related-window)))
     (when (and (setq window related-window)
	       (window-live-p window)
	       (or (eq buffer (window-buffer 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 alist))))





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#70949: display-buffer-choose-some-window
  2024-05-24  9:32                             ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2024-05-24 17:38                               ` Juri Linkov
  2024-05-26  8:54                                 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 37+ messages in thread
From: Juri Linkov @ 2024-05-24 17:38 UTC (permalink / raw)
  To: martin rudalics; +Cc: 70949

>> This makes the behavior more predictable: the user will know that all
>> buffers will be displayed in the most recently used window, so the user
>> can switch to that window before continuing to navigate buffers.
>
> Not really.  The window switched to becomes the selected window and the
> 'mru' window used will be the window where the user was working before
> the switch due to NOT-SELECTED being t.

I meant switching to the window to instruct display-buffer what window
to use as mru, then switch back to the rgrep window.

>>> Then maybe a separate category for rgrep buffers could help here.
>>
>> This is not about rgrep buffers.
>
> Consider the completely untested action function below supposed to be
> called with a (related-window . rgrep) alist argument.

We already have 'previous-window' that I'm using for a long time,
and it works nicely with such configuration:

(defvar-local display-buffer-previous-window nil)

(defun display-buffer-from-grep-p (_buffer-name _action)
  (with-current-buffer (window-buffer)
    (and (memq this-command '(compile-goto-error))
         (derived-mode-p '(compilation-mode)))))

(add-to-list 'display-buffer-alist
             '(display-buffer-from-grep-p
               display-buffer-in-previous-window
               (previous-window . display-buffer-previous-window)
               (inhibit-same-window . nil))
             ;; Append to not override display-buffer-same-window
             'append)

(define-advice compile-goto-error (:around (ofun &rest args) previous-window)
  (let ((buffer (current-buffer)))
    (apply ofun args)
    (with-current-buffer buffer
      (setq-local display-buffer-previous-window (selected-window)))))

But this is very complicated configuration.  So I wanted to help people
to do basically the same with much simpler setting that overrides
the hard-coded 'lru' with just '(some-window . mru)'.

The only problem with '(some-window . mru)' is that its NOT-SELECTED is t,
so this excludes the very useful case of displaying the buffer
in the same selected window.  For example, with 'previous-window'
I often visit rgrep results in the same window where the rgrep buffer
was displayed.  This keeps everything confined to one window.

I see that in your display-buffer-in-related-window
'related-window' is a window parameter.  I think this is
much better than a buffer-local variable that I used above.
But a new alist 'related-window' should also update
the 'related-window' window parameter in 'post-command-hook'
like 'post-command-select-window' does.

Then the customization for users would be very simple:

(add-to-list 'display-buffer-alist
             '((category . rgrep) (display-buffer-in-related-window)))

Or maybe a better name would be 'display-buffer-in-last-window'?

In any case this looks like a workable solution
that will create a connection between windows.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#70949: display-buffer-choose-some-window
  2024-05-24 17:38                               ` Juri Linkov
@ 2024-05-26  8:54                                 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2024-05-27 17:52                                   ` Juri Linkov
  0 siblings, 1 reply; 37+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-05-26  8:54 UTC (permalink / raw)
  To: Juri Linkov; +Cc: 70949

 > I meant switching to the window to instruct display-buffer what window
 > to use as mru, then switch back to the rgrep window.

Who would switch to the window?  The user or 'display-buffer' itself?

 > We already have 'previous-window' that I'm using for a long time,
 > and it works nicely with such configuration:
 >
 > (defvar-local display-buffer-previous-window nil)
 >
 > (defun display-buffer-from-grep-p (_buffer-name _action)
 >    (with-current-buffer (window-buffer)
 >      (and (memq this-command '(compile-goto-error))
 >           (derived-mode-p '(compilation-mode)))))
 >
 > (add-to-list 'display-buffer-alist
 >               '(display-buffer-from-grep-p
 >                 display-buffer-in-previous-window
 >                 (previous-window . display-buffer-previous-window)
 >                 (inhibit-same-window . nil))
 >               ;; Append to not override display-buffer-same-window
 >               'append)
 >
 > (define-advice compile-goto-error (:around (ofun &rest args) previous-window)
 >    (let ((buffer (current-buffer)))
 >      (apply ofun args)
 >      (with-current-buffer buffer
 >        (setq-local display-buffer-previous-window (selected-window)))))
 >
 > But this is very complicated configuration.  So I wanted to help people
 > to do basically the same with much simpler setting that overrides
 > the hard-coded 'lru' with just '(some-window . mru)'.

I think that's what we want here and it should cover all sorts of
'next-error-function' too.  But 'get-mru-window' won't cut it.

 > The only problem with '(some-window . mru)' is that its NOT-SELECTED is t,
 > so this excludes the very useful case of displaying the buffer
 > in the same selected window.  For example, with 'previous-window'
 > I often visit rgrep results in the same window where the rgrep buffer
 > was displayed.  This keeps everything confined to one window.

We could provide two basic modes: One mode where the compilation, grep,
or occur buffer is always kept visible and the file buffers are
displayed in one or a few other windows.  And a mode where only one
window is used.

In either case we could use a window parameter, say 'next-window', that
indicates that this window shall be used for the next 'display-buffer'
call with a non-nil 'next-window' alist entry.  The value could be
'grep', 'occur' 'compile' or whatever we want so a user could do, for
example, a grep within the outer context of analyzing compilation
output.

I see the following problems:

- How to set up the 'next-window' parameter in the first call of a given
   context.  IIUC we don't have a unique starting function for
   establishing a suitable context of a series of related calls.  So
   both, 'compile-goto-error' and 'next-error', would have to call
   'display-buffer' with an appropriate 'next-window' entry.  For me,
   it's been always confusing that 'compilation-next-error' does not
   display the source buffer while 'next-error' does.

- How to remove/reset the parameter after the last call.  'quit-window'
   should probably do that, but I'm not sure.

- How to "nest" contexts when windows are shared.  If the same window
   were used for displaying grep results within a compilation results
   context, the 'next-window' parameter would have to become a list and
   'quit-window' should probably pop an entry from it.

martin





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#70949: display-buffer-choose-some-window
  2024-05-26  8:54                                 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2024-05-27 17:52                                   ` Juri Linkov
  2024-05-28  8:05                                     ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 37+ messages in thread
From: Juri Linkov @ 2024-05-27 17:52 UTC (permalink / raw)
  To: martin rudalics; +Cc: 70949

>> I meant switching to the window to instruct display-buffer what window
>> to use as mru, then switch back to the rgrep window.
>
> Who would switch to the window?  The user or 'display-buffer' itself?

The user.

>> We already have 'previous-window' that I'm using for a long time,
>> and it works nicely with such configuration:
>>
>> (defvar-local display-buffer-previous-window nil)
>>
>> (defun display-buffer-from-grep-p (_buffer-name _action)
>>    (with-current-buffer (window-buffer)
>>      (and (memq this-command '(compile-goto-error))
>>           (derived-mode-p '(compilation-mode)))))
>>
>> (add-to-list 'display-buffer-alist
>>               '(display-buffer-from-grep-p
>>                 display-buffer-in-previous-window
>>                 (previous-window . display-buffer-previous-window)
>>                 (inhibit-same-window . nil))
>>               ;; Append to not override display-buffer-same-window
>>               'append)
>>
>> (define-advice compile-goto-error (:around (ofun &rest args) previous-window)
>>    (let ((buffer (current-buffer)))
>>      (apply ofun args)
>>      (with-current-buffer buffer
>>        (setq-local display-buffer-previous-window (selected-window)))))
>>
>> But this is very complicated configuration.  So I wanted to help people
>> to do basically the same with much simpler setting that overrides
>> the hard-coded 'lru' with just '(some-window . mru)'.
>
> I think that's what we want here and it should cover all sorts of
> 'next-error-function' too.  But 'get-mru-window' won't cut it.

I agree that 'get-mru-window' is too limited.

>> The only problem with '(some-window . mru)' is that its NOT-SELECTED is t,
>> so this excludes the very useful case of displaying the buffer
>> in the same selected window.  For example, with 'previous-window'
>> I often visit rgrep results in the same window where the rgrep buffer
>> was displayed.  This keeps everything confined to one window.
>
> We could provide two basic modes: One mode where the compilation, grep,
> or occur buffer is always kept visible and the file buffers are
> displayed in one or a few other windows.  And a mode where only one
> window is used.
>
> In either case we could use a window parameter, say 'next-window', that
> indicates that this window shall be used for the next 'display-buffer'
> call with a non-nil 'next-window' alist entry.  The value could be
> 'grep', 'occur' 'compile' or whatever we want so a user could do, for
> example, a grep within the outer context of analyzing compilation
> output.

Ok, I will throw out everything that I did, and will restart with your
function display-buffer-in-related-window.

> I see the following problems:
>
> - How to set up the 'next-window' parameter in the first call of a given
>   context.  IIUC we don't have a unique starting function for
>   establishing a suitable context of a series of related calls.  So
>   both, 'compile-goto-error' and 'next-error', would have to call
>   'display-buffer' with an appropriate 'next-window' entry.  For me,
>   it's been always confusing that 'compilation-next-error' does not
>   display the source buffer while 'next-error' does.

I don't understand why 'compilation-next-error' does not display
the source buffer?

> - How to remove/reset the parameter after the last call.  'quit-window'
>   should probably do that, but I'm not sure.
>
> - How to "nest" contexts when windows are shared.  If the same window
>   were used for displaying grep results within a compilation results
>   context, the 'next-window' parameter would have to become a list and
>   'quit-window' should probably pop an entry from it.

Nothing so complicated needed.  I will just adapt your starting point with
display-buffer-in-related-window to the useful configuration above.

Currently the main question is where to add display-buffer-in-related-window?
It should be added to display-buffer-fallback-action between
display-buffer-in-previous-window and display-buffer-use-some-window?
If not, then users should add it by customizing display-buffer-base-action?





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#70949: display-buffer-choose-some-window
  2024-05-27 17:52                                   ` Juri Linkov
@ 2024-05-28  8:05                                     ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2024-05-28 16:19                                       ` Juri Linkov
  0 siblings, 1 reply; 37+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-05-28  8:05 UTC (permalink / raw)
  To: Juri Linkov; +Cc: 70949

 >> Who would switch to the window?  The user or 'display-buffer' itself?
 >
 > The user.

Tedious to explain and not really practicable.

 > I don't understand why 'compilation-next-error' does not display
 > the source buffer?

Historical reasons, I suppose.

 > Currently the main question is where to add display-buffer-in-related-window?
 > It should be added to display-buffer-fallback-action between
 > display-buffer-in-previous-window and display-buffer-use-some-window?
 > If not, then users should add it by customizing display-buffer-base-action?

Hopefully it can be merged into 'display-buffer-in-previous-window'.

Some random thoughts:

I suppose that 'next-error-find-buffer' should determine the "does the
selected window show the next-/previous-error capable buffer" predicate
and, together with some option, set up either the one window fits all
strategy (whether a file buffer should be shown in the results window)
or a multiple windows strategy.  Always considering the possibility that
the results buffer is nowhere shown initially.

If 'next-error-find-buffer' finds a buffer other than
'next-error-last-buffer', it should probably tell 'display-buffer' that
we apparently start a new series of results, that we shall push the last
buffer somehow, start the new series of results, and pop to that last
buffer when quitting the new series.  'display-buffer' should then reuse
the "same" window in the one-window case or the file window in the
multiple windows case to continue with the previous series of results.
Whether and how to handle the case where two series of results should be
displayed in some intertwined fashion is another question.

One thing we should consider carefully is how to side-step the special
case that one of the file buffers is already shown in some other window
and how to either avoid showing the same buffer twice or rather show it
twice when the next error location is not shown in that other window.

martin





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#70949: display-buffer-choose-some-window
  2024-05-28  8:05                                     ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2024-05-28 16:19                                       ` Juri Linkov
  2024-05-29  8:49                                         ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 37+ messages in thread
From: Juri Linkov @ 2024-05-28 16:19 UTC (permalink / raw)
  To: martin rudalics; +Cc: 70949

>> Currently the main question is where to add display-buffer-in-related-window?
>> It should be added to display-buffer-fallback-action between
>> display-buffer-in-previous-window and display-buffer-use-some-window?
>> If not, then users should add it by customizing display-buffer-base-action?
>
> Hopefully it can be merged into 'display-buffer-in-previous-window'.

This is exactly what I already use in ~/.emacs, and it works nicely.
Any chance to add something like this optionally to window.el?

(defvar-local display-buffer-previous-window nil)

(add-to-list 'display-buffer-alist
             '((category . compilation)
               display-buffer-in-previous-window
               (previous-window . display-buffer-previous-window)))

(define-advice compile-goto-error (:around (ofun &rest args) previous-window)
  (let ((buffer (current-buffer)))
    (apply ofun args)
    (with-current-buffer buffer
      (setq-local display-buffer-previous-window (selected-window)))))

The main problem is where to set this buffer-local variable
(I think better to use the buffer-local variable instead
of the window parameter since visiting results from rgrep
is a property of the buffer, not the window).
Instead of the advice like above, 'display-buffer-previous-window'
should be set in every buffer displayed by 'display-buffer'.
Isn't setting this variable in all buffers too excessive?
But I see no other way because the user might want to
force displaying the results in the same rgrep window, then
display-buffer-in-previous-window should reuse the same window.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#70949: display-buffer-choose-some-window
  2024-05-28 16:19                                       ` Juri Linkov
@ 2024-05-29  8:49                                         ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2024-05-30  6:34                                           ` Juri Linkov
  0 siblings, 1 reply; 37+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-05-29  8:49 UTC (permalink / raw)
  To: Juri Linkov; +Cc: 70949

 > This is exactly what I already use in ~/.emacs, and it works nicely.
 > Any chance to add something like this optionally to window.el?
 >
 > (defvar-local display-buffer-previous-window nil)
 >
 > (add-to-list 'display-buffer-alist
 >               '((category . compilation)
 >                 display-buffer-in-previous-window
 >                 (previous-window . display-buffer-previous-window)))
 >
 > (define-advice compile-goto-error (:around (ofun &rest args) previous-window)
 >    (let ((buffer (current-buffer)))
 >      (apply ofun args)
 >      (with-current-buffer buffer
 >        (setq-local display-buffer-previous-window (selected-window)))))
 >
 > The main problem is where to set this buffer-local variable
 > (I think better to use the buffer-local variable instead
 > of the window parameter since visiting results from rgrep
 > is a property of the buffer, not the window).
 > Instead of the advice like above, 'display-buffer-previous-window'
 > should be set in every buffer displayed by 'display-buffer'.
 > Isn't setting this variable in all buffers too excessive?
 > But I see no other way because the user might want to
 > force displaying the results in the same rgrep window, then
 > display-buffer-in-previous-window should reuse the same window.

We are talking about displaying, in one and the same window, buffers
whose only relationship is that they appear in the results list of
compilation or grep output.  That's why I think that a buffer-local
variable doesn't make sense here.  It works for 'compile-goto-error' but
only if, as a user, you invoke 'display-buffer' from the results window.
If you are in the file window and want to display the next file, you
have to go back to the results window.  If you use one window to show
results and files, you have to redisplay the results in that window
first.  All this is tedious, especially given the fact that 'next-error'
already can guess from where to get the name of the next file to show.

I think we need a unified framework that supports 'compile-goto-error'
and 'next-error' out of the box, where the later command can be invoked
from anywhere (although the key-binding in the results buffer is
obscured by 'compilation-next-error').  Which means that we should use a
global variable, say 'compilation-previous-window', that these commands
use to show the next file buffer.

This variable should be set up by the first invocation of either
'compile-goto-error' or 'next-error' and should be reset by
'quit-window' and 'delete-window'.  In addition, we'd need
'grep-previous-window' and 'occur-previous-window' variables and
whatever else falls into this category.

'next-error' could first determine, as it does now, to which category
the user request belongs.  If it's the compilation category, it consults
'compilation-previous-window' and, if that's a live window, calls
'display-buffer' with a 'display-buffer-in-previous-window' action and
'compilation-previous-window' as 'previous-window' action alist entry.
If it's not a live window, it has to first find or make a suitable
window, set 'compilation-previous-window' to that window and maybe mark
the window as softly dedicated so it won't get used too soon by other
'display-buffer' calls.

Whether all this should be done by 'next-error' or within
'display-buffer' is to decide.  In the latter case, 'next-error' could
pass to 'display-buffer' a 'previous-window' entry whose value is
something like the symbol 'compilation-previous-window' and
'display-buffer' would have to do the work I sketched above.  This has
the advantage that 'compile-goto-error' could use the same underlying
mechanism and no code would be duplicated.  The disadvantage is that
people who know about the inner working of compilation buffers and
'next-error' would have to work within window.el.

martin





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#70949: display-buffer-choose-some-window
  2024-05-29  8:49                                         ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2024-05-30  6:34                                           ` Juri Linkov
  2024-05-30  8:54                                             ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 37+ messages in thread
From: Juri Linkov @ 2024-05-30  6:34 UTC (permalink / raw)
  To: martin rudalics; +Cc: 70949

> We are talking about displaying, in one and the same window, buffers
> whose only relationship is that they appear in the results list of
> compilation or grep output.  That's why I think that a buffer-local
> variable doesn't make sense here.  It works for 'compile-goto-error' but
> only if, as a user, you invoke 'display-buffer' from the results window.
> If you are in the file window and want to display the next file, you
> have to go back to the results window.  If you use one window to show
> results and files, you have to redisplay the results in that window
> first.  All this is tedious, especially given the fact that 'next-error'
> already can guess from where to get the name of the next file to show.
>
> I think we need a unified framework that supports 'compile-goto-error'
> and 'next-error' out of the box, where the later command can be invoked
> from anywhere (although the key-binding in the results buffer is
> obscured by 'compilation-next-error').  Which means that we should use a
> global variable, say 'compilation-previous-window', that these commands
> use to show the next file buffer.
>
> This variable should be set up by the first invocation of either
> 'compile-goto-error' or 'next-error' and should be reset by
> 'quit-window' and 'delete-window'.  In addition, we'd need
> 'grep-previous-window' and 'occur-previous-window' variables and
> whatever else falls into this category.
>
> 'next-error' could first determine, as it does now, to which category
> the user request belongs.  If it's the compilation category, it consults
> 'compilation-previous-window' and, if that's a live window, calls
> 'display-buffer' with a 'display-buffer-in-previous-window' action and
> 'compilation-previous-window' as 'previous-window' action alist entry.
> If it's not a live window, it has to first find or make a suitable
> window, set 'compilation-previous-window' to that window and maybe mark
> the window as softly dedicated so it won't get used too soon by other
> 'display-buffer' calls.
>
> Whether all this should be done by 'next-error' or within
> 'display-buffer' is to decide.  In the latter case, 'next-error' could
> pass to 'display-buffer' a 'previous-window' entry whose value is
> something like the symbol 'compilation-previous-window' and
> 'display-buffer' would have to do the work I sketched above.  This has
> the advantage that 'compile-goto-error' could use the same underlying
> mechanism and no code would be duplicated.  The disadvantage is that
> people who know about the inner working of compilation buffers and
> 'next-error' would have to work within window.el.

Sorry, I don't understand why the design should be limited to
compile-goto-error/next-error only.  I have the same problem with many
other commands.  For example, vc-diff from such buffers as *vc-dir*,
*vc-change-log* opens the diff buffer in unpredictable windows, every
time choosing another window that makes the window management unusable
(need to quit the buffer displayed in the wrong window and re-run the
diff command again).

As a unified framework we could provide a new defcustom with a list
of categories for which display-buffer will set a buffer-local variable
or the window parameter 'previous-window', then the next invocations
of the same command will reuse it.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#70949: display-buffer-choose-some-window
  2024-05-30  6:34                                           ` Juri Linkov
@ 2024-05-30  8:54                                             ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2024-05-31  6:18                                               ` Juri Linkov
  0 siblings, 1 reply; 37+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-05-30  8:54 UTC (permalink / raw)
  To: Juri Linkov; +Cc: 70949

 > Sorry, I don't understand why the design should be limited to
 > compile-goto-error/next-error only.

That's what I keep saying here all the time.

 > As a unified framework we could provide a new defcustom with a list
 > of categories for which display-buffer will set a buffer-local variable
 > or the window parameter 'previous-window', then the next invocations
 > of the same command will reuse it.

I don't think that one defcustom will do.  And if we try building on
what 'next-error' finds for us, buffer-local variables won't help
either.

The common underlying principle is that a user starts an operation to
display several file-visiting buffers in a row triggered by some sort of
operation on these files like a compilation, grep, or version control
action.  That action usually produces a buffer I call "results buffer"
and sequentially scanning that buffer will produce "file buffers" that
should be handled in a specific way.  So we need:

- A method for extracting a list of file names from the results buffer
   (not needed if the results buffer contains them already but in my
   experience these file names are often relative only).  Obviously, this
   is already done for each of the contexts we want to address but it
   would be nice to have some unified approach here: A list of absolute
   file names and a pointer to which is the one to be displayed next.

- A method for displaying the first file buffer.  It will decide whether
   the file buffer replaces the results buffer in its window, uses some
   other window on the same frame or even another frame...  And it will
   set up the '...-previous-window' variable specifying the window that
   should be used for displaying the remaining file buffers.

- Key-bindings for displaying the next and previous file buffers from
   _any_ window selected.  Ideally, these would be M-n and M-p.

- A method for quitting.  Deleting the file buffer window (or frame) is
   one way to do that.  Invoking M-n with the last file buffer current
   could be another way - possibly after a 'quit' prompt.  Otherwise,
   'quit-window' and the 'quit-restore' parameter should handle that,
   where the latter would have to be set up when displaying the first
   file buffer.

The major customizable thing I see here is the method for displaying the
first file buffer and I think that that should be done for each type of
results buffer separately.

martin





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#70949: display-buffer-choose-some-window
  2024-05-30  8:54                                             ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2024-05-31  6:18                                               ` Juri Linkov
  2024-05-31  9:45                                                 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 37+ messages in thread
From: Juri Linkov @ 2024-05-31  6:18 UTC (permalink / raw)
  To: martin rudalics; +Cc: 70949

> And it will set up the '...-previous-window' variable

Not a variable, but a window parameter.  A buffer-local variable
can't be used because for example 'vc-diff-internal' uses such
call sequence:

  (set-buffer buffer)
  (pop-to-buffer (current-buffer))

so 'display-buffer' is called from 'pop-to-buffer' in the wrong buffer.

Therefore, when using a window parameter, the solution is very simple
like in the following patch that allows a short customization:

  (setq display-buffer-base-action
        '(nil (set-previous-window . t)))

Then users can use anything such as 'C-x 4 1' or 'C-x 4 4',
and after this the subsequent navigation will reuse
the same window.

Even 'next-error-no-select' ('n' and 'p' keys in the grep buffer)
that hard-codes 'inhibit-same-window', still uses the mru window,
because it's 'second-best-window'.

diff --git a/lisp/window.el b/lisp/window.el
index b014be6a7cf..ff12a2225b5 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -7883,7 +7888,8 @@ display-buffer
 specified by the ACTION argument."
   (interactive (list (read-buffer "Display buffer: " (other-buffer))
 		     (if current-prefix-arg t)))
-  (let ((buffer (if (bufferp buffer-or-name)
+  (let ((old-selected-window (selected-window))
+        (buffer (if (bufferp buffer-or-name)
 		    buffer-or-name
 		  (get-buffer buffer-or-name)))
         (buf-name (if (bufferp buffer-or-name)
@@ -7933,6 +7938,8 @@ display-buffer
                         (select-window old-selected-window)))
                     (remove-hook 'post-command-hook postfun))))
           (add-hook 'post-command-hook postfun)))
+      (when (cdr (assq 'set-previous-window alist))
+        (set-window-parameter old-selected-window 'previous-window window))
       (and (windowp window) window))))
 
 (defun display-buffer-other-frame (buffer)
@@ -8638,6 +8645,7 @@ display-buffer-in-previous-window
 		  (display-buffer-reuse-frames 0)
 		  (t (last-nonminibuffer-frame))))
          (previous-window (cdr (assq 'previous-window alist)))
+         (set-previous-window (cdr (assq 'set-previous-window alist)))
 	 best-window second-best-window window)
     ;; Scan windows whether they have shown the buffer recently.
     (catch 'best
@@ -8654,6 +8662,9 @@ display-buffer-in-previous-window
     (when (and previous-window (symbolp previous-window)
                (boundp previous-window))
       (setq previous-window (symbol-value previous-window)))
+    (when-let ((set-previous-window)
+               (prev (window-parameter (selected-window) 'previous-window)))
+      (setq previous-window prev))
     (when (and (setq window previous-window)
 	       (window-live-p window)
 	       (or (eq buffer (window-buffer window))






^ permalink raw reply related	[flat|nested] 37+ messages in thread

* bug#70949: display-buffer-choose-some-window
  2024-05-31  6:18                                               ` Juri Linkov
@ 2024-05-31  9:45                                                 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2024-06-02  6:39                                                   ` Juri Linkov
  0 siblings, 1 reply; 37+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-05-31  9:45 UTC (permalink / raw)
  To: Juri Linkov; +Cc: 70949

 > Not a variable, but a window parameter.  A buffer-local variable
 > can't be used because for example 'vc-diff-internal' uses such
 > call sequence:
 >
 >    (set-buffer buffer)
 >    (pop-to-buffer (current-buffer))
 >
 > so 'display-buffer' is called from 'pop-to-buffer' in the wrong buffer.

So what we want to do here is to make 'vc-diff' work in the context of
'vc-dir'.  There you have a set of "interesting" files you want to
compare with their base versions.  'vc-diff' calls 'vc-deduce-fileset'
to find the set of files to compare.  If that function returns a single
file or a single-file list, we continue as usual.  But if that function
returns a list of files, 'vc-diff' knows that it is in or enters a mode
where it should use one and the same window to show a sequence of diffs.

In that latter case, 'vc-diff' could pass an extra optional argument to
'vc-diff-internal', telling it that it has to call 'pop-to-buffer' with
a 'display-buffer-in-previous-window' action and a 'previous-window'
alist entry whose value is 'vc-diff'.  That's all 'vc-diff' can do.

'display-buffer-in-previous-window' could now try to find a window whose
'previous-window' parameter is (or includes the value) 'vc-diff'.  If it
finds such a window, it displays the diff there.  Otherwise, it has to
display the diff in the usual manner - just as if the 'previous-window'
entry didn't exist.  In either case 'display-buffer' would set (or add)
a '(previous-window . vc-diff) parameter for the window used.

'quit-window' would eventually remove that 'previous-window' parameter
or entry provided the buffer shown in the window is a vc-diff buffer.

Note: I don't know how 'vc-deduce-fileset' gets the next file in a set
of files to diff.  I simply assume that it does TRT here.

martin





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#70949: display-buffer-choose-some-window
  2024-05-31  9:45                                                 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2024-06-02  6:39                                                   ` Juri Linkov
  2024-06-04  8:20                                                     ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 37+ messages in thread
From: Juri Linkov @ 2024-06-02  6:39 UTC (permalink / raw)
  To: martin rudalics; +Cc: 70949

>> Not a variable, but a window parameter.  A buffer-local variable
>> can't be used because for example 'vc-diff-internal' uses such
>> call sequence:
>>
>>    (set-buffer buffer)
>>    (pop-to-buffer (current-buffer))
>>
>> so 'display-buffer' is called from 'pop-to-buffer' in the wrong buffer.
>
> So what we want to do here is to make 'vc-diff' work in the context of
> 'vc-dir'.  There you have a set of "interesting" files you want to
> compare with their base versions.  'vc-diff' calls 'vc-deduce-fileset'
> to find the set of files to compare.  If that function returns a single
> file or a single-file list, we continue as usual.  But if that function
> returns a list of files, 'vc-diff' knows that it is in or enters a mode
> where it should use one and the same window to show a sequence of diffs.

But display-buffer displays buffers, not files.

> In that latter case, 'vc-diff' could pass an extra optional argument to
> 'vc-diff-internal', telling it that it has to call 'pop-to-buffer' with
> a 'display-buffer-in-previous-window' action and a 'previous-window'
> alist entry whose value is 'vc-diff'.  That's all 'vc-diff' can do.

This doesn't look like a nice design to require changing the signatures
of vc functions.

> 'display-buffer-in-previous-window' could now try to find a window whose
> 'previous-window' parameter is (or includes the value) 'vc-diff'.  If it
> finds such a window, it displays the diff there.  Otherwise, it has to
> display the diff in the usual manner - just as if the 'previous-window'
> entry didn't exist.  In either case 'display-buffer' would set (or add)
> a '(previous-window . vc-diff) parameter for the window used.
>
> 'quit-window' would eventually remove that 'previous-window' parameter
> or entry provided the buffer shown in the window is a vc-diff buffer.
>
> Note: I don't know how 'vc-deduce-fileset' gets the next file in a set
> of files to diff.  I simply assume that it does TRT here.

I think such design looks overly complicated.  I hoped for something
much simpler by adding just a few lines to window.el.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#70949: display-buffer-choose-some-window
  2024-06-02  6:39                                                   ` Juri Linkov
@ 2024-06-04  8:20                                                     ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2024-06-04 16:43                                                       ` Juri Linkov
  0 siblings, 1 reply; 37+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-06-04  8:20 UTC (permalink / raw)
  To: Juri Linkov; +Cc: 70949

 >> In that latter case, 'vc-diff' could pass an extra optional argument to
 >> 'vc-diff-internal', telling it that it has to call 'pop-to-buffer' with
 >> a 'display-buffer-in-previous-window' action and a 'previous-window'
 >> alist entry whose value is 'vc-diff'.  That's all 'vc-diff' can do.
 >
 > This doesn't look like a nice design to require changing the signatures
 > of vc functions.

We don't have to.  But then we can forget the idea of identifying the
first in a sequence of related operations.

 > I think such design looks overly complicated.  I hoped for something
 > much simpler by adding just a few lines to window.el.

We have to make up our minds on what we want.  I think the primary aim
is to display a series of related buffers in one and the same window.
Where and when do we want that?  So far we discussed two functions -
'vc-diff' and 'compile-goto-error'.  I think that at the very least we
have to encompass all flavors of 'next-error' as well.

Then we can look into how the clients of 'display-buffer' can support
it.  Finally, we can decide how many lines of code we have to change in
window.el.

martin





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#70949: display-buffer-choose-some-window
  2024-06-04  8:20                                                     ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2024-06-04 16:43                                                       ` Juri Linkov
  2024-06-05  8:46                                                         ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 37+ messages in thread
From: Juri Linkov @ 2024-06-04 16:43 UTC (permalink / raw)
  To: martin rudalics; +Cc: 70949

>> I think such design looks overly complicated.  I hoped for something
>> much simpler by adding just a few lines to window.el.
>
> We have to make up our minds on what we want.  I think the primary aim
> is to display a series of related buffers in one and the same window.

The most reliable way to identify a series of related buffers
is to set a buffer-local variable in the origin buffer
to the window where outgoing buffers are displayed.

> Where and when do we want that?  So far we discussed two functions -
> 'vc-diff' and 'compile-goto-error'.  I think that at the very least we
> have to encompass all flavors of 'next-error' as well.

The feature should work for any possible command or buffer,
not limited to the small set of particular commands.

> Then we can look into how the clients of 'display-buffer' can support
> it.  Finally, we can decide how many lines of code we have to change in
> window.el.

Ideally, the users need to express their preference by a single alist entry.
For example:

  (use-previous-window . t) -- then all outgoing buffers will be displayed
                               in the same window

  (use-mru-window . t) -- then all outgoing buffers will be displayed
                          in the most recently used window
                          instead of the default lru

Or maybe a unified alist entry:

  (prefer . previous-window)
  (prefer . mru-window)





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#70949: display-buffer-choose-some-window
  2024-06-04 16:43                                                       ` Juri Linkov
@ 2024-06-05  8:46                                                         ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2024-06-05 16:48                                                           ` Juri Linkov
  0 siblings, 1 reply; 37+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-06-05  8:46 UTC (permalink / raw)
  To: Juri Linkov; +Cc: 70949

 > The most reliable way to identify a series of related buffers
 > is to set a buffer-local variable in the origin buffer
 > to the window where outgoing buffers are displayed.

How would this work in the case of 'vc-dir'?  There you have a status
buffer whose buffer-local variable you probably want to set.  You call
'vc-diff' which calls 'vc-diff-internal' which eventually calls
'pop-to-buffer' which chooses the window of the outgoing buffer.  How
would you set up the variable in this scenario?

 > Ideally, the users need to express their preference by a single alist entry.
 > For example:
 >
 >    (use-previous-window . t) -- then all outgoing buffers will be displayed
 >                                 in the same window
 >
 >    (use-mru-window . t) -- then all outgoing buffers will be displayed
 >                            in the most recently used window
 >                            instead of the default lru
 >
 > Or maybe a unified alist entry:
 >
 >    (prefer . previous-window)
 >    (prefer . mru-window)

It's trivial to set up such an association for "*vc-diff*".  But what
would you do when calling 'vc-diff' with a different BUFFER argument?
Which kind of association would you set up for showing the next error
buffer in compilation output?

martin





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#70949: display-buffer-choose-some-window
  2024-06-05  8:46                                                         ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2024-06-05 16:48                                                           ` Juri Linkov
  2024-06-06  9:19                                                             ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 37+ messages in thread
From: Juri Linkov @ 2024-06-05 16:48 UTC (permalink / raw)
  To: martin rudalics; +Cc: 70949

>> The most reliable way to identify a series of related buffers
>> is to set a buffer-local variable in the origin buffer
>> to the window where outgoing buffers are displayed.
>
> How would this work in the case of 'vc-dir'?  There you have a status
> buffer whose buffer-local variable you probably want to set.  You call
> 'vc-diff' which calls 'vc-diff-internal' which eventually calls
> 'pop-to-buffer' which chooses the window of the outgoing buffer.  How
> would you set up the variable in this scenario?

The same way as the condition function allows to check
the original buffer, e.g. customization to show
outgoing 'vc-diff' buffers in the same window
where the 'vc-dir' was displayed:

  (defun display-buffer-from-vc-dir-p (_buffer-name _action)
    (with-current-buffer (window-buffer)
      (derived-mode-p '(vc-dir-mode))))

  (add-to-list 'display-buffer-alist
               '(display-buffer-from-vc-dir-p
                 display-buffer-same-window
                 (inhibit-same-window . nil)))

This means using

  (with-current-buffer (window-buffer)
    (setq-local display-buffer-previous-window (selected-window)))

after every buffer display from the original buffer.

>> Ideally, the users need to express their preference by a single alist entry.
>> For example:
>>
>>    (use-previous-window . t) -- then all outgoing buffers will be displayed
>>                                 in the same window
>>
>>    (use-mru-window . t) -- then all outgoing buffers will be displayed
>>                            in the most recently used window
>>                            instead of the default lru
>>
>> Or maybe a unified alist entry:
>>
>>    (prefer . previous-window)
>>    (prefer . mru-window)
>
> It's trivial to set up such an association for "*vc-diff*".  But what
> would you do when calling 'vc-diff' with a different BUFFER argument?
> Which kind of association would you set up for showing the next error
> buffer in compilation output?

The displayed buffer has no significance.  The buffer-local variable
will be set in the original buffer to the value of the displayed window.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#70949: display-buffer-choose-some-window
  2024-06-05 16:48                                                           ` Juri Linkov
@ 2024-06-06  9:19                                                             ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2024-06-07  6:37                                                               ` Juri Linkov
  0 siblings, 1 reply; 37+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-06-06  9:19 UTC (permalink / raw)
  To: Juri Linkov; +Cc: 70949

 > The same way as the condition function allows to check
 > the original buffer, e.g. customization to show
 > outgoing 'vc-diff' buffers in the same window
 > where the 'vc-dir' was displayed:
 >
 >    (defun display-buffer-from-vc-dir-p (_buffer-name _action)
 >      (with-current-buffer (window-buffer)
 >        (derived-mode-p '(vc-dir-mode))))

This means that the user has to always go back from the *vc-diff* window
back to a *vc-dir* window in order to tell what to show next in the
*vc-diff* window.  It completely defeats the idea of the advanced
mechanics of 'next-error' which autonomously would guess what to show
next in the *vc-diff* window without having to continuously hop back to
the *vc-dir* buffer.

I hardly use 'vc-diff' because I'm not good at reading diffs.  When I
want to view the differences of a fileset controlled by git I first run
git status in a shell window and, based on its output, ediff on all
involved files.  The crucial aspect here is that whenever I'm done with
watching the differences of one file, I'd never want to go back to the
shell window because that would disrupt my ediff layout with two side by
side windows and the ediff status window on bottom.  Rather I use a
mechanism that gets me directly from a layout showing the (presumably
last) diff for the current file to a layout showing the first diff for
the next file listed by git status.

martin





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#70949: display-buffer-choose-some-window
  2024-06-06  9:19                                                             ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2024-06-07  6:37                                                               ` Juri Linkov
  2024-06-07  8:23                                                                 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 37+ messages in thread
From: Juri Linkov @ 2024-06-07  6:37 UTC (permalink / raw)
  To: martin rudalics; +Cc: 70949

> This means that the user has to always go back from the *vc-diff* window
> back to a *vc-dir* window in order to tell what to show next in the
> *vc-diff* window.  It completely defeats the idea of the advanced
> mechanics of 'next-error' which autonomously would guess what to show
> next in the *vc-diff* window without having to continuously hop back to
> the *vc-dir* buffer.
>
> I hardly use 'vc-diff' because I'm not good at reading diffs.  When I
> want to view the differences of a fileset controlled by git I first run
> git status in a shell window and, based on its output, ediff on all
> involved files.  The crucial aspect here is that whenever I'm done with
> watching the differences of one file, I'd never want to go back to the
> shell window because that would disrupt my ediff layout with two side by
> side windows and the ediff status window on bottom.  Rather I use a
> mechanism that gets me directly from a layout showing the (presumably
> last) diff for the current file to a layout showing the first diff for
> the next file listed by git status.

Then let's install the first patch for (nil . ((some-window . mru)))
that is not so controversial.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#70949: display-buffer-choose-some-window
  2024-06-07  6:37                                                               ` Juri Linkov
@ 2024-06-07  8:23                                                                 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2024-06-07 16:45                                                                   ` Juri Linkov
  0 siblings, 1 reply; 37+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-06-07  8:23 UTC (permalink / raw)
  To: Juri Linkov; +Cc: 70949

 > Then let's install the first patch for (nil . ((some-window . mru)))
 > that is not so controversial.

OK with me.

martin





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#70949: display-buffer-choose-some-window
  2024-06-07  8:23                                                                 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2024-06-07 16:45                                                                   ` Juri Linkov
  2024-06-08  9:12                                                                     ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 37+ messages in thread
From: Juri Linkov @ 2024-06-07 16:45 UTC (permalink / raw)
  To: martin rudalics; +Cc: 70949

close 70949 30.0.50
thanks

>> Then let's install the first patch for (nil . ((some-window . mru)))
>> that is not so controversial.
>
> OK with me.

Very nice!  So the original patch is pushed, and now the OP can happily use:

  (setq display-buffer-base-action '(nil . ((some-window . mru))))

and I can use:

  (defvar-local display-buffer-last-window nil)
  (setq display-buffer-base-action
        '(nil . ((some-window
                  . (lambda (_buffer alist)
                      (let ((last-window (buffer-local-value
                                          'display-buffer-last-window
                                          (window-buffer))))
                        (or (and (window-live-p last-window) last-window)
                            (get-mru-window nil nil t))))))))
  (define-advice display-buffer-record-window (:after (type window buffer))
    (with-current-buffer (window-buffer)
      (setq-local display-buffer-last-window window)))

that works nicely even for showing buffers repeatedly
in the selected window.  And all commands are supported,
even to show diffs from vc-dir.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#70949: display-buffer-choose-some-window
  2024-06-07 16:45                                                                   ` Juri Linkov
@ 2024-06-08  9:12                                                                     ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2024-06-09 17:04                                                                       ` Juri Linkov
  0 siblings, 1 reply; 37+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-06-08  9:12 UTC (permalink / raw)
  To: Juri Linkov; +Cc: 70949

Consider these minor changes for the Elisp manual

The above describes the behavior when the @code{some-window} @var{alist}
entry is @code{lru} or @code{nil} which is the default.  Another
possible value is @code{mru}.  If, for example,
@code{display-buffer-base-action} is customized to @w{@code{(nil
. ((some-window . mru)))}}, then this function will prefer the most
recently used window.  This will try to display several buffers from
consecutive calls of @code{display-buffer} in the same window.  Consider
a configuration of three or more windows where a user wants to consult,
in a non-selected window, one after the other, the results of a query
spread among several buffers.  With the @code{lru} strategy, Emacs may
continuously choose another window because the least recently used
window changes with every call of @code{display-buffer-use-some-window}.
With the @code{mru} strategy, the window chosen would always remain the
same, resulting in a predictable user experience.

and this for the NEWS entry:

*** New action alist entry 'some-window' for 'display-buffer'.
It specifies which window 'display-buffer-use-some-window' should prefer.
For example, when 'display-buffer-base-action' is customized to
'(nil . ((some-window . mru)))', then a buffer will be displayed
in the same most recently used window from consecutive calls of
'display-buffer' (in a configuration with more than two windows).

martin





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#70949: display-buffer-choose-some-window
  2024-06-08  9:12                                                                     ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2024-06-09 17:04                                                                       ` Juri Linkov
  0 siblings, 0 replies; 37+ messages in thread
From: Juri Linkov @ 2024-06-09 17:04 UTC (permalink / raw)
  To: martin rudalics; +Cc: 70949

> Consider these minor changes for the Elisp manual
>
> The above describes the behavior when the @code{some-window} @var{alist}
> entry is @code{lru} or @code{nil} which is the default.  Another
> possible value is @code{mru}.  If, for example,
> @code{display-buffer-base-action} is customized to @w{@code{(nil
> . ((some-window . mru)))}}, then this function will prefer the most
> recently used window.  This will try to display several buffers from
> consecutive calls of @code{display-buffer} in the same window.  Consider
> a configuration of three or more windows where a user wants to consult,
> in a non-selected window, one after the other, the results of a query
> spread among several buffers.  With the @code{lru} strategy, Emacs may
> continuously choose another window because the least recently used
> window changes with every call of @code{display-buffer-use-some-window}.
> With the @code{mru} strategy, the window chosen would always remain the
> same, resulting in a predictable user experience.
>
> and this for the NEWS entry:
>
> *** New action alist entry 'some-window' for 'display-buffer'.
> It specifies which window 'display-buffer-use-some-window' should prefer.
> For example, when 'display-buffer-base-action' is customized to
> '(nil . ((some-window . mru)))', then a buffer will be displayed
> in the same most recently used window from consecutive calls of
> 'display-buffer' (in a configuration with more than two windows).

Thanks, now pushed.





^ permalink raw reply	[flat|nested] 37+ messages in thread

end of thread, other threads:[~2024-06-09 17:04 UTC | newest]

Thread overview: 37+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-05-14 16:56 bug#70949: display-buffer-choose-some-window Juri Linkov
2024-05-15  8:06 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-05-15 16:49   ` Juri Linkov
2024-05-16  8:20     ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-05-17  6:40       ` Juri Linkov
2024-05-18  9:21         ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-05-20  6:15           ` Juri Linkov
2024-05-20  8:01             ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-05-20 16:54               ` Juri Linkov
2024-05-21  8:21                 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-05-21 17:18                   ` Juri Linkov
2024-05-22  7:39                     ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-05-23  6:16                       ` Juri Linkov
2024-05-23  7:22                         ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-05-23 17:27                           ` Juri Linkov
2024-05-24  9:32                             ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-05-24 17:38                               ` Juri Linkov
2024-05-26  8:54                                 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-05-27 17:52                                   ` Juri Linkov
2024-05-28  8:05                                     ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-05-28 16:19                                       ` Juri Linkov
2024-05-29  8:49                                         ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-05-30  6:34                                           ` Juri Linkov
2024-05-30  8:54                                             ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-05-31  6:18                                               ` Juri Linkov
2024-05-31  9:45                                                 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-06-02  6:39                                                   ` Juri Linkov
2024-06-04  8:20                                                     ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-06-04 16:43                                                       ` Juri Linkov
2024-06-05  8:46                                                         ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-06-05 16:48                                                           ` Juri Linkov
2024-06-06  9:19                                                             ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-06-07  6:37                                                               ` Juri Linkov
2024-06-07  8:23                                                                 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-06-07 16:45                                                                   ` Juri Linkov
2024-06-08  9:12                                                                     ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-06-09 17:04                                                                       ` Juri Linkov

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).