diff options
| author | Martin Rudalics | 2025-02-24 10:17:10 +0100 |
|---|---|---|
| committer | Martin Rudalics | 2025-02-24 10:17:10 +0100 |
| commit | a205d554522340e23540bdda63c80965ddd64951 (patch) | |
| tree | 9471cb689522c7ce705a18eff9bd8845c99981e9 | |
| parent | be60601ae884214503c4f958a74cebc27e8381b6 (diff) | |
| download | emacs-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.texi | 50 | ||||
| -rw-r--r-- | etc/NEWS | 11 | ||||
| -rw-r--r-- | lisp/window.el | 107 |
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 | |||
| 2697 | to eliminate this discrepancy. | 2697 | to eliminate this discrepancy. |
| 2698 | @end defun | 2698 | @end defun |
| 2699 | 2699 | ||
| 2700 | @defun get-buffer-window-list &optional buffer-or-name minibuf all-frames | 2700 | The following function can tell for a specific window whether its buffer |
| 2701 | shares the text of some other buffer (@pxref{Indirect Buffers}). | ||
| 2702 | |||
| 2703 | @defun window-indirect-buffer-p &optional window buffer-or-name | ||
| 2704 | This function returns non-@code{nil} if @var{window} is indirectly | ||
| 2705 | related to @var{buffer-or-name}. @var{window} must be a live window and | ||
| 2706 | defaults to the selected window. @var{buffer-or-name} may be a buffer | ||
| 2707 | or 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 | ||
| 2710 | following conditions hold: | ||
| 2711 | |||
| 2712 | @itemize @bullet | ||
| 2713 | @item | ||
| 2714 | @var{buffer-or-name} specifies an indirect buffer and @var{window}'s | ||
| 2715 | buffer is its base buffer. | ||
| 2716 | |||
| 2717 | @item | ||
| 2718 | @var{window}'s buffer is an indirect buffer whose base buffer is the | ||
| 2719 | buffer specified by @var{buffer-or-name}. | ||
| 2720 | |||
| 2721 | @item | ||
| 2722 | Both, @var{window}'s buffer and the buffer specified by | ||
| 2723 | @var{buffer-or-name}, are indirect buffer's sharing the same base | ||
| 2724 | buffer. | ||
| 2725 | @end itemize | ||
| 2726 | |||
| 2727 | It 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 | ||
| 2701 | This function returns a list of all windows currently displaying | 2731 | This 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 |
| 2703 | name of an existing buffer. If omitted or @code{nil}, it defaults to | 2733 | name 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 | |||
| 2709 | meanings as in the function @code{next-window} (@pxref{Cyclic Window | 2739 | meanings as in the function @code{next-window} (@pxref{Cyclic Window |
| 2710 | Ordering}). Note that the @var{all-frames} argument does @emph{not} | 2740 | Ordering}). Note that the @var{all-frames} argument does @emph{not} |
| 2711 | behave exactly like in @code{get-buffer-window}. | 2741 | behave exactly like in @code{get-buffer-window}. |
| 2742 | |||
| 2743 | The optional argument @var{indirect} non-@code{nil} means to append to | ||
| 2744 | the list of windows showing @var{buffer-or-name} a list of all windows | ||
| 2745 | that are indirectly related to @var{buffer-or-name}, that is, windows | ||
| 2746 | for which @code{window-indirect-buffer-p} (see above) with the window | ||
| 2747 | and the buffer specified by @var{buffer-or-name} as arguments returns | ||
| 2748 | non-@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. | |||
| 3165 | If this function chooses a window on another frame, it makes that | 3202 | If this function chooses a window on another frame, it makes that |
| 3166 | frame visible and, unless @var{alist} contains an | 3203 | frame 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 | |||
| 3206 | If @var{alist} has a non-@code{nil} @code{reuse-indirect} entry and no | ||
| 3207 | window showing @var{buffer} has been found, this function tries to find | ||
| 3208 | a window that is indirectly related to @var{buffer}---a window for which | ||
| 3209 | @code{window-indirect-buffer-p} (@pxref{Buffers and Windows}) with the | ||
| 3210 | window and @var{buffer} as arguments returns non-@code{nil}. If such a | ||
| 3211 | window has been found and the @sc{cdr} of the @code{reuse-indirect} | ||
| 3212 | entry equals the symbol @code{buffer}, it does not replace the buffer of | ||
| 3213 | that window with @var{buffer} but returns the window with its old buffer | ||
| 3214 | in place. Otherwise, it puts @var{buffer} into that window and returns | ||
| 3215 | that 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 |
| @@ -247,6 +247,17 @@ landscape shape for instance, Emacs could split horizontally before | |||
| 247 | splitting vertically. The default setting preserves Emacs historical | 247 | splitting vertically. The default setting preserves Emacs historical |
| 248 | behavior to try to split vertically first. | 248 | behavior to try to split vertically first. |
| 249 | 249 | ||
| 250 | +++ | ||
| 251 | *** New argument INDIRECT for 'get-buffer-window-list'. | ||
| 252 | With this argument non-nil, 'get-buffer-window-list' will include in the | ||
| 253 | return value windows whose buffers share their text with BUFFER-OR-NAME. | ||
| 254 | |||
| 255 | +++ | ||
| 256 | *** New 'display-buffer' action alist entry 'reuse-indirect'. | ||
| 257 | With such an entry, 'display-buffer-reuse-window' may also choose a | ||
| 258 | window 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. | ||
| 2621 | WINDOW must be a live window and defaults to the selected window. | ||
| 2622 | BUFFER-OR-NAME may be a buffer or the name of an existing buffer and | ||
| 2623 | defaults to the current buffer. | ||
| 2624 | |||
| 2625 | WINODW is indirectly related to BUFFER-OR-NAME if one of the following | ||
| 2626 | conditions 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 | |||
| 2637 | Return 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. |
| 2621 | BUFFER-OR-NAME may be a buffer or the name of an existing buffer | 2650 | BUFFER-OR-NAME may be a buffer or the name of an existing buffer |
| 2622 | and defaults to the current buffer. If the selected window displays | 2651 | and 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 | ||
| 2647 | Anything else means consider all windows on the selected frame | 2676 | Anything else means consider all windows on the selected frame |
| 2648 | and no others." | 2677 | and no others. |
| 2678 | |||
| 2679 | INDIRECT non-nil means to append to the list of windows showing | ||
| 2680 | BUFFER-OR-NAME a list of all windows that are indirectly related to | ||
| 2681 | BUFFER-OR-NAME, that is, windows for which `window-indirect-buffer-p' | ||
| 2682 | with the window and the buffer specified by BUFFER-OR-NAME as arguments | ||
| 2683 | returns 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 | |||
| 8348 | event that a window on another frame is chosen, avoid raising | 8388 | event that a window on another frame is chosen, avoid raising |
| 8349 | that frame. | 8389 | that frame. |
| 8350 | 8390 | ||
| 8391 | If ALIST has a non-nil `reuse-indirect' entry and no window showing | ||
| 8392 | BUFFER has been found, try to find a window that is indirectly related | ||
| 8393 | to BUFFER and return that window. This would be a window for which | ||
| 8394 | `window-indirect-buffer-p' with the window and BUFFER as arguments | ||
| 8395 | returns non-nil. If a suitable window has been found and the cdr of the | ||
| 8396 | entry equals the symbol `buffer', do not replace the buffer of that | ||
| 8397 | window with BUFFER but return the window with its old buffer in place. | ||
| 8398 | Otherwise, put BUFFER into that window and return the window. | ||
| 8399 | |||
| 8351 | This is an action function for buffer display, see Info | 8400 | This is an action function for buffer display, see Info |
| 8352 | node `(elisp) Buffer Display Action Functions'. It should be | 8401 | node `(elisp) Buffer Display Action Functions'. It should be |
| 8353 | called only by `display-buffer' or a function directly or | 8402 | called only by `display-buffer' or a function directly or |
| 8354 | indirectly called by the latter." | 8403 | indirectly 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))))))) |