aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Rudalics2025-02-24 10:17:10 +0100
committerMartin Rudalics2025-02-24 10:17:10 +0100
commita205d554522340e23540bdda63c80965ddd64951 (patch)
tree9471cb689522c7ce705a18eff9bd8845c99981e9
parentbe60601ae884214503c4f958a74cebc27e8381b6 (diff)
downloademacs-a205d554522340e23540bdda63c80965ddd64951.tar.gz
emacs-a205d554522340e23540bdda63c80965ddd64951.zip
Optionally have 'display-buffer' reuse windows of indirect buffers
* lisp/window.el (window-indirect-buffer-p): New function. (get-buffer-window-list): New argument INDIRECT. (display-buffer-reuse-window): New alist entry 'reuse-indirect' to reuse a window indirectly related to the BUFFER argument. * doc/lispref/windows.texi (Buffers and Windows): Describe new function 'window-indirect-buffer-p' and new argument INDIRECT of 'get-buffer-window-list'. (Buffer Display Action Functions): Describe new action alist entry 'reuse-indirect'. * etc/NEWS: Announce new argument for 'get-buffer-window-list' and new 'display-buffer' action alist entry 'reuse-indirect'.
-rw-r--r--doc/lispref/windows.texi50
-rw-r--r--etc/NEWS11
-rw-r--r--lisp/window.el107
3 files changed, 144 insertions, 24 deletions
diff --git a/doc/lispref/windows.texi b/doc/lispref/windows.texi
index 6c4e59d448f..5c0db6d4877 100644
--- a/doc/lispref/windows.texi
+++ b/doc/lispref/windows.texi
@@ -2697,7 +2697,37 @@ Ordering}). This function may be changed in a future version of Emacs
2697to eliminate this discrepancy. 2697to eliminate this discrepancy.
2698@end defun 2698@end defun
2699 2699
2700@defun get-buffer-window-list &optional buffer-or-name minibuf all-frames 2700The following function can tell for a specific window whether its buffer
2701shares the text of some other buffer (@pxref{Indirect Buffers}).
2702
2703@defun window-indirect-buffer-p &optional window buffer-or-name
2704This function returns non-@code{nil} if @var{window} is indirectly
2705related to @var{buffer-or-name}. @var{window} must be a live window and
2706defaults to the selected window. @var{buffer-or-name} may be a buffer
2707or the name of an existing buffer and defaults to the current buffer.
2708
2709@var{window} is indirectly related to @var{buffer-or-name} if one of the
2710following conditions hold:
2711
2712@itemize @bullet
2713@item
2714@var{buffer-or-name} specifies an indirect buffer and @var{window}'s
2715buffer is its base buffer.
2716
2717@item
2718@var{window}'s buffer is an indirect buffer whose base buffer is the
2719buffer specified by @var{buffer-or-name}.
2720
2721@item
2722Both, @var{window}'s buffer and the buffer specified by
2723@var{buffer-or-name}, are indirect buffer's sharing the same base
2724buffer.
2725@end itemize
2726
2727It returns @code{nil} if none of the above holds.
2728@end defun
2729
2730@defun get-buffer-window-list &optional buffer-or-name minibuf all-frames indirect
2701This function returns a list of all windows currently displaying 2731This function returns a list of all windows currently displaying
2702@var{buffer-or-name}. @var{buffer-or-name} should be a buffer or the 2732@var{buffer-or-name}. @var{buffer-or-name} should be a buffer or the
2703name of an existing buffer. If omitted or @code{nil}, it defaults to 2733name of an existing buffer. If omitted or @code{nil}, it defaults to
@@ -2709,6 +2739,13 @@ The arguments @var{minibuf} and @var{all-frames} have the same
2709meanings as in the function @code{next-window} (@pxref{Cyclic Window 2739meanings as in the function @code{next-window} (@pxref{Cyclic Window
2710Ordering}). Note that the @var{all-frames} argument does @emph{not} 2740Ordering}). Note that the @var{all-frames} argument does @emph{not}
2711behave exactly like in @code{get-buffer-window}. 2741behave exactly like in @code{get-buffer-window}.
2742
2743The optional argument @var{indirect} non-@code{nil} means to append to
2744the list of windows showing @var{buffer-or-name} a list of all windows
2745that are indirectly related to @var{buffer-or-name}, that is, windows
2746for which @code{window-indirect-buffer-p} (see above) with the window
2747and the buffer specified by @var{buffer-or-name} as arguments returns
2748non-@code{nil}.
2712@end defun 2749@end defun
2713 2750
2714@deffn Command replace-buffer-in-windows &optional buffer-or-name 2751@deffn Command replace-buffer-in-windows &optional buffer-or-name
@@ -3165,6 +3202,17 @@ searches just the selected frame.
3165If this function chooses a window on another frame, it makes that 3202If this function chooses a window on another frame, it makes that
3166frame visible and, unless @var{alist} contains an 3203frame visible and, unless @var{alist} contains an
3167@code{inhibit-switch-frame} entry, raises that frame if necessary. 3204@code{inhibit-switch-frame} entry, raises that frame if necessary.
3205
3206If @var{alist} has a non-@code{nil} @code{reuse-indirect} entry and no
3207window showing @var{buffer} has been found, this function tries to find
3208a window that is indirectly related to @var{buffer}---a window for which
3209@code{window-indirect-buffer-p} (@pxref{Buffers and Windows}) with the
3210window and @var{buffer} as arguments returns non-@code{nil}. If such a
3211window has been found and the @sc{cdr} of the @code{reuse-indirect}
3212entry equals the symbol @code{buffer}, it does not replace the buffer of
3213that window with @var{buffer} but returns the window with its old buffer
3214in place. Otherwise, it puts @var{buffer} into that window and returns
3215that window.
3168@end defun 3216@end defun
3169 3217
3170@defun display-buffer-reuse-mode-window buffer alist 3218@defun display-buffer-reuse-mode-window buffer alist
diff --git a/etc/NEWS b/etc/NEWS
index 4a89b9abe6f..29abfaf1126 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -247,6 +247,17 @@ landscape shape for instance, Emacs could split horizontally before
247splitting vertically. The default setting preserves Emacs historical 247splitting vertically. The default setting preserves Emacs historical
248behavior to try to split vertically first. 248behavior to try to split vertically first.
249 249
250+++
251*** New argument INDIRECT for 'get-buffer-window-list'.
252With this argument non-nil, 'get-buffer-window-list' will include in the
253return value windows whose buffers share their text with BUFFER-OR-NAME.
254
255+++
256*** New 'display-buffer' action alist entry 'reuse-indirect'.
257With such an entry, 'display-buffer-reuse-window' may also choose a
258window whose buffer shares text with the buffer to display.
259
260
250** Frames 261** Frames
251 262
252+++ 263+++
diff --git a/lisp/window.el b/lisp/window.el
index f94558c6850..7fdde3ee18c 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -2616,7 +2616,36 @@ selected frame and no others."
2616 (setq best-window window)))) 2616 (setq best-window window))))
2617 best-window)) 2617 best-window))
2618 2618
2619(defun get-buffer-window-list (&optional buffer-or-name minibuf all-frames) 2619(defun window-indirect-buffer-p (&optional window buffer-or-name)
2620 "Return non-nil if specified WINDOW is indirectly related to BUFFER-OR-NAME.
2621WINDOW must be a live window and defaults to the selected window.
2622BUFFER-OR-NAME may be a buffer or the name of an existing buffer and
2623defaults to the current buffer.
2624
2625WINODW is indirectly related to BUFFER-OR-NAME if one of the following
2626conditions hold:
2627
2628- BUFFER-OR-NAME specifies an indirect buffer and WINDOW's buffer is its
2629 base buffer.
2630
2631- WINDOW's buffer is an indirect buffer whose base buffer is the buffer
2632 specified by BUFFER-OR-NAME.
2633
2634- Both, WINDOW's buffer and the buffer specified by BUFFER-OR-NAME, are
2635 indirect buffer's sharing the same base buffer.
2636
2637Return nil if none of the above holds."
2638 (let* ((window (window-normalize-window window t))
2639 (window-buffer (window-buffer window))
2640 (window-base-buffer (buffer-base-buffer window-buffer))
2641 (buffer (window-normalize-buffer buffer-or-name))
2642 (buffer-base-buffer (buffer-base-buffer buffer)))
2643 (or (eq buffer-base-buffer window-buffer)
2644 (eq window-base-buffer buffer)
2645 (and buffer-base-buffer
2646 (eq buffer-base-buffer window-base-buffer)))))
2647
2648(defun get-buffer-window-list (&optional buffer-or-name minibuf all-frames indirect)
2620 "Return list of all windows displaying BUFFER-OR-NAME, or nil if none. 2649 "Return list of all windows displaying BUFFER-OR-NAME, or nil if none.
2621BUFFER-OR-NAME may be a buffer or the name of an existing buffer 2650BUFFER-OR-NAME may be a buffer or the name of an existing buffer
2622and defaults to the current buffer. If the selected window displays 2651and defaults to the current buffer. If the selected window displays
@@ -2645,12 +2674,23 @@ non-nil values of ALL-FRAMES have special meanings:
2645- A frame means consider all windows on that frame only. 2674- A frame means consider all windows on that frame only.
2646 2675
2647Anything else means consider all windows on the selected frame 2676Anything else means consider all windows on the selected frame
2648and no others." 2677and no others.
2678
2679INDIRECT non-nil means to append to the list of windows showing
2680BUFFER-OR-NAME a list of all windows that are indirectly related to
2681BUFFER-OR-NAME, that is, windows for which `window-indirect-buffer-p'
2682with the window and the buffer specified by BUFFER-OR-NAME as arguments
2683returns non-nil."
2649 (let ((buffer (window-normalize-buffer buffer-or-name)) 2684 (let ((buffer (window-normalize-buffer buffer-or-name))
2685 (window-list (window-list-1 (selected-window) minibuf all-frames))
2650 windows) 2686 windows)
2651 (dolist (window (window-list-1 (selected-window) minibuf all-frames)) 2687 (dolist (window window-list)
2652 (when (eq (window-buffer window) buffer) 2688 (when (eq (window-buffer window) buffer)
2653 (setq windows (cons window windows)))) 2689 (setq windows (cons window windows))))
2690 (when indirect
2691 (dolist (window window-list)
2692 (when (window-indirect-buffer-p window buffer)
2693 (setq windows (cons window windows)))))
2654 (nreverse windows))) 2694 (nreverse windows)))
2655 2695
2656(defun minibuffer-window-active-p (window) 2696(defun minibuffer-window-active-p (window)
@@ -8348,35 +8388,56 @@ If ALIST has a non-nil `inhibit-switch-frame' entry, then in the
8348event that a window on another frame is chosen, avoid raising 8388event that a window on another frame is chosen, avoid raising
8349that frame. 8389that frame.
8350 8390
8391If ALIST has a non-nil `reuse-indirect' entry and no window showing
8392BUFFER has been found, try to find a window that is indirectly related
8393to BUFFER and return that window. This would be a window for which
8394`window-indirect-buffer-p' with the window and BUFFER as arguments
8395returns non-nil. If a suitable window has been found and the cdr of the
8396entry equals the symbol `buffer', do not replace the buffer of that
8397window with BUFFER but return the window with its old buffer in place.
8398Otherwise, put BUFFER into that window and return the window.
8399
8351This is an action function for buffer display, see Info 8400This is an action function for buffer display, see Info
8352node `(elisp) Buffer Display Action Functions'. It should be 8401node `(elisp) Buffer Display Action Functions'. It should be
8353called only by `display-buffer' or a function directly or 8402called only by `display-buffer' or a function directly or
8354indirectly called by the latter." 8403indirectly called by the latter."
8355 (let* ((alist-entry (assq 'reusable-frames alist)) 8404 (let* ((reusable-frames (assq 'reusable-frames alist))
8356 (frames (cond (alist-entry (cdr alist-entry)) 8405 (reuse-indirect (assq 'reuse-indirect alist))
8406 (frames (cond (reusable-frames (cdr reusable-frames))
8357 ((window--pop-up-frames alist) 8407 ((window--pop-up-frames alist)
8358 0) 8408 0)
8359 (display-buffer-reuse-frames 0) 8409 (display-buffer-reuse-frames 0)
8360 (t (last-nonminibuffer-frame)))) 8410 (t (last-nonminibuffer-frame))))
8361 (window (if (and (eq buffer (window-buffer)) 8411 (inhibit-same (cdr (assq 'inhibit-same-window alist)))
8362 (not (cdr (assq 'inhibit-same-window alist)))) 8412 (window
8363 (selected-window) 8413 ;; Avoid calling 'get-buffer-window-list' if the selected
8364 ;; Preferably use a window on the selected frame, 8414 ;; window already shows BUFFER and can be used.
8365 ;; if such a window exists (Bug#36680). 8415 (if (and (eq buffer (window-buffer)) (not inhibit-same))
8366 (let* ((windows (delq (selected-window) 8416 (selected-window)
8367 (get-buffer-window-list 8417 ;; Preferably use a window on the selected frame,
8368 buffer 'nomini frames))) 8418 ;; if such a window exists (Bug#36680).
8369 (first (car windows)) 8419 (let* ((windows-raw
8370 (this-frame (selected-frame))) 8420 (get-buffer-window-list
8371 (cond 8421 buffer 'nomini frames reuse-indirect))
8372 ((eq (window-frame first) this-frame) 8422 (windows (if inhibit-same
8373 first) 8423 (delq (selected-window) windows-raw)
8374 ((catch 'found 8424 windows-raw))
8375 (dolist (next (cdr windows)) 8425 (first (car windows))
8376 (when (eq (window-frame next) this-frame) 8426 (this-frame (selected-frame)))
8377 (throw 'found next))))) 8427 (cond
8378 (t first)))))) 8428 ((eq (window-frame first) this-frame)
8429 first)
8430 ((catch 'found
8431 (dolist (next (cdr windows))
8432 (when (eq (window-frame next) this-frame)
8433 (throw 'found next)))))
8434 (t first))))))
8379 (when (window-live-p window) 8435 (when (window-live-p window)
8436 (when (and (eq (cdr reuse-indirect) 'buffer)
8437 (not (eq (window-buffer window) buffer)))
8438 ;; Pretend we were asking for a window showing the buffer of
8439 ;; that window.
8440 (setq buffer (window-buffer window)))
8380 (prog1 (window--display-buffer buffer window 'reuse alist) 8441 (prog1 (window--display-buffer buffer window 'reuse alist)
8381 (unless (cdr (assq 'inhibit-switch-frame alist)) 8442 (unless (cdr (assq 'inhibit-switch-frame alist))
8382 (window--maybe-raise-frame (window-frame window))))))) 8443 (window--maybe-raise-frame (window-frame window)))))))