mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-02-17 18:37:33 +00:00
New buffer display action function 'display-buffer-in-direction'
* lisp/window.el (windows-sharing-edge) (window--try-to-split-window-in-direction) (display-buffer-in-direction): New functions. * doc/lispref/windows.texi (Buffer Display Action Functions): Describe new action function 'display-buffer-in-direction'. (Buffer Display Action Alists): Describe new entry 'direction'. Amend description of 'window' entry. * etc/NEWS: Mention 'display-buffer-in-direction' and 'direction' and 'window' action alist entries.
This commit is contained in:
parent
b87e5eea1d
commit
8783becbba
3 changed files with 229 additions and 1 deletions
|
|
@ -2601,6 +2601,63 @@ window and displaying the buffer in that window. It can fail if all
|
|||
windows are dedicated to other buffers (@pxref{Dedicated Windows}).
|
||||
@end defun
|
||||
|
||||
@defun display-buffer-in-direction buffer alist
|
||||
This function tries to display @var{buffer} at a location specified by
|
||||
@var{alist}. For this purpose, @var{alist} should contain a
|
||||
@code{direction} entry whose value is one of @code{left}, @code{above}
|
||||
(or @code{up}), @code{right} and @code{below} (or @code{down}). Other
|
||||
values are usually interpreted as @code{below}.
|
||||
|
||||
If @var{alist} also contains a @code{window} entry, its value
|
||||
specifies a reference window. That value can be a special symbol like
|
||||
@code{main} which stands for the selected frame's main window
|
||||
(@pxref{Side Window Options and Functions}) or @code{root} standing
|
||||
for the selected frame's root window (@pxref{Windows and Frames}). It
|
||||
can also specify an arbitrary valid window. Any other value (or
|
||||
omitting the @code{window} entry entirely) means to use the selected
|
||||
window as reference window.
|
||||
|
||||
This function first tries to reuse a window in the specified direction
|
||||
that already shows @var{buffer}. If no such window exists, it tries
|
||||
to split the reference window in order to produce a new window in the
|
||||
specified direction. If this fails as well, it will try to display
|
||||
@var{buffer} in an existing window in the specified direction. In
|
||||
either case, the window chosen will appear on the side of the
|
||||
reference window specified by the @code{direction} entry, sharing at
|
||||
least one edge with the reference window.
|
||||
|
||||
If the reference window is live, the edge the chosen window will share
|
||||
with it is always the opposite of the one specified by the
|
||||
@code{direction} entry. For example, if the value of the
|
||||
@code{direction} entry is @code{left}, the chosen window's right edge
|
||||
coordinate (@pxref{Coordinates and Windows}) will equal the reference
|
||||
window's left edge coordinate.
|
||||
|
||||
If the reference window is internal, a reused window must share with
|
||||
it the edge specified by the @code{direction} entry. Hence if, for
|
||||
example, the reference window is the frame's root window and the value
|
||||
of the @code{direction} entry is @code{left}, a reused window must be
|
||||
on the left of the frame. This means that the left edge coordinate of
|
||||
the chosen window and that of the reference window are the same.
|
||||
|
||||
A new window, however, will be created by splitting the reference
|
||||
window such that the chosen window will share the opposite edge with
|
||||
the reference window. In our example, a new root window would be
|
||||
created with a new live window and the reference window as its
|
||||
children. The chosen window's right edge coordinate would then equal
|
||||
the left edge coordinate of the reference window. Its left edge
|
||||
coordinate would equal the left edge coordinate of the frame's new
|
||||
root window.
|
||||
|
||||
Four special values for @code{direction} entries allow to implicitly
|
||||
specify the selected frame's main window as the reference window:
|
||||
@code{leftmost}, @code{top}, @code{rightmost} and @code{bottom}. This
|
||||
means that instead of, for example, @w{@code{(direction . left)
|
||||
(window . main)}} one can just specify @w{@code{(direction
|
||||
. leftmost)}}. An existing @code{window} @var{alist} entry is ignored
|
||||
in such cases.
|
||||
@end defun
|
||||
|
||||
@defun display-buffer-below-selected buffer alist
|
||||
This function tries to display @var{buffer} in a window below the
|
||||
selected window. If there is a window below the selected one and that
|
||||
|
|
@ -2934,12 +2991,20 @@ If non-@code{nil}, the value specifies the slot of the side window
|
|||
supposed to display the buffer. This entry is used only by
|
||||
@code{display-buffer-in-side-window}.
|
||||
|
||||
@vindex direction@r{, a buffer display action alist entry}
|
||||
@item direction
|
||||
The value specifies a direction which, together with a @code{window}
|
||||
entry, allows @code{display-buffer-in-direction} to determine the
|
||||
location of the window to display the buffer.
|
||||
|
||||
@vindex window@r{, a buffer display action alist entry}
|
||||
@item window
|
||||
The value specifies a window that is in some way related to the window
|
||||
chosen by @code{display-buffer}. This entry is currently used by
|
||||
@code{display-buffer-in-atom-window} to indicate the window on whose
|
||||
side the new window shall be created.
|
||||
side the new window shall be created. It is also used by
|
||||
@code{display-buffer-in-direction} to specify the reference window on
|
||||
whose side the resulting window shall appear.
|
||||
|
||||
@vindex allow-no-window@r{, a buffer display action alist entry}
|
||||
@item allow-no-window
|
||||
|
|
|
|||
15
etc/NEWS
15
etc/NEWS
|
|
@ -1778,6 +1778,11 @@ detailed explanation of the new behavior.
|
|||
This option allows to automatically resize minibuffer-only frames
|
||||
similarly to how minibuffer windows are resized on "normal" frames.
|
||||
|
||||
+++
|
||||
** New buffer display action function 'display-buffer-in-direction'.
|
||||
This function allows to specify the location of the window chosen by
|
||||
'display-buffer' in various ways.
|
||||
|
||||
+++
|
||||
** New buffer display action alist entry 'dedicated'.
|
||||
Such an entry allows to specify the dedicated status of a window
|
||||
|
|
@ -1789,6 +1794,16 @@ Such an entry allows to specify a minimum height of the window used
|
|||
for displaying a buffer. 'display-buffer-below-selected' is the only
|
||||
action function to respect it at the moment.
|
||||
|
||||
+++
|
||||
** New buffer display action alist entry 'direction'.
|
||||
This entry is used to specify the location of the window chosen by
|
||||
'display-buffer-in-direction'.
|
||||
|
||||
+++
|
||||
** Additional meaning of display action alist entry 'window'.
|
||||
A 'window' entry can now also specify a reference window for
|
||||
'display-buffer-in-direction'.
|
||||
|
||||
+++
|
||||
** The function 'assoc-delete-all' now takes an optional predicate argument.
|
||||
|
||||
|
|
|
|||
148
lisp/window.el
148
lisp/window.el
|
|
@ -7534,6 +7534,152 @@ be added to ALIST."
|
|||
(unless (cdr (assq 'inhibit-switch-frame alist))
|
||||
(window--maybe-raise-frame frame)))))
|
||||
|
||||
(defun windows-sharing-edge (&optional window edge within)
|
||||
"Return list of live windows sharing the same edge with WINDOW.
|
||||
WINDOW must be a valid window and defaults to the selected one.
|
||||
EDGE stands for the edge to share and must be either 'left',
|
||||
'above', 'right' or 'below'. Omitted or nil, EDGE defaults to
|
||||
'left'.
|
||||
|
||||
WITHIN nil means to find a live window that shares the opposite
|
||||
EDGE with WINDOW. For example, if EDGE equals 'left', WINDOW has
|
||||
to share (part of) the right edge of any window returned. WITHIN
|
||||
non-nil means to find all live windows that share the same EDGE
|
||||
with WINDOW (Window must be internal in this case). So if EDGE
|
||||
equals 'left', WINDOW's left edge has to fully encompass the left
|
||||
edge of any window returned."
|
||||
(setq window (window-normalize-window window))
|
||||
(setq edge (or edge 'left))
|
||||
(when (and within (window-live-p window))
|
||||
(error "Cannot share edge from within live window %s" window))
|
||||
(let ((window-edges (window-edges window nil nil t))
|
||||
(horizontal (memq edge '(left right)))
|
||||
(n (pcase edge
|
||||
('left 0) ('above 1) ('right 2) ('below 3))))
|
||||
(unless (numberp n)
|
||||
(error "Invalid EDGE %s" edge))
|
||||
(let ((o (mod (+ 2 n) 4))
|
||||
(p (if horizontal 1 0))
|
||||
(q (if horizontal 3 2))
|
||||
windows)
|
||||
(walk-window-tree
|
||||
(lambda (other)
|
||||
(let ((other-edges (window-edges other nil nil t)))
|
||||
(when (and (not (eq window other))
|
||||
(= (nth n window-edges)
|
||||
(nth (if within n o) other-edges))
|
||||
(cond
|
||||
((= (nth p window-edges) (nth p other-edges)))
|
||||
((< (nth p window-edges) (nth p other-edges))
|
||||
(< (nth p other-edges) (nth q window-edges)))
|
||||
(t
|
||||
(< (nth p window-edges) (nth q other-edges)))))
|
||||
(setq windows (cons other windows)))))
|
||||
(window-frame window) nil 'nomini)
|
||||
(reverse windows))))
|
||||
|
||||
(defun window--try-to-split-window-in-direction (window direction alist)
|
||||
"Try to split WINDOW in DIRECTION.
|
||||
DIRECTION is passed as SIDE argument to `split-window-no-error'.
|
||||
ALIST is a buffer display alist."
|
||||
(and (not (frame-parameter (window-frame window) 'unsplittable))
|
||||
(let* ((window-combination-limit
|
||||
;; When `window-combination-limit' equals
|
||||
;; `display-buffer' or equals `resize-window' and a
|
||||
;; `window-height' or `window-width' alist entry are
|
||||
;; present, bind it to t so resizing steals space
|
||||
;; preferably from the window that was split.
|
||||
(if (or (eq window-combination-limit 'display-buffer)
|
||||
(and (eq window-combination-limit 'window-size)
|
||||
(or (cdr (assq 'window-height alist))
|
||||
(cdr (assq 'window-width alist)))))
|
||||
t
|
||||
window-combination-limit))
|
||||
(new-window (split-window-no-error window nil direction)))
|
||||
(and (window-live-p new-window) new-window))))
|
||||
|
||||
(defun display-buffer-in-direction (buffer alist)
|
||||
"Try to display BUFFER in a direction specified by ALIST.
|
||||
ALIST has to contain a 'direction' entry whose value should be
|
||||
one of 'left', 'above' (or 'up'), 'right', and 'below' (or
|
||||
'down'). Other values are usually interpreted as 'below'.
|
||||
|
||||
If ALIST also contains a 'window' entry, its value specifies a
|
||||
reference window. That value can be a special symbol like
|
||||
'main' (which stands for the selected frame's main window) or
|
||||
'root' (standings for the selected frame's root window) or an
|
||||
arbitrary valid window. Any other value (or omitting the
|
||||
'window' entry) means to use the selected window as reference
|
||||
window.
|
||||
|
||||
This function tries to reuse or split a window such that the
|
||||
window produced this way is on the side of the reference window
|
||||
specified by the 'direction' entry.
|
||||
|
||||
Four special values for 'direction' entries allow to implicitly
|
||||
specify the selected frame's main window as reference window:
|
||||
'leftmost', 'top', 'rightmost' and 'bottom'. Hence, instead of
|
||||
'(direction . left) (window . main)' one can simply write
|
||||
'(direction . leftmost)'."
|
||||
(let ((direction (cdr (assq 'direction alist))))
|
||||
(when direction
|
||||
(let ((window (cdr (assq 'window alist)))
|
||||
within windows other-window-shows-buffer other-window)
|
||||
;; Sanitize WINDOW.
|
||||
(cond
|
||||
((or (eq window 'main)
|
||||
(memq direction '(top bottom leftmost rightmost)))
|
||||
(setq window (window-main-window)))
|
||||
((eq window 'root)
|
||||
(setq window (frame-root-window)))
|
||||
((window-valid-p window))
|
||||
(t
|
||||
(setq window (selected-window))))
|
||||
(setq within (not (window-live-p window)))
|
||||
;; Sanitize DIRECTION
|
||||
(cond
|
||||
((memq direction '(left above right below)))
|
||||
((eq direction 'leftmost)
|
||||
(setq direction 'left))
|
||||
((memq direction '(top up))
|
||||
(setq direction 'above))
|
||||
((eq direction 'rightmost)
|
||||
(setq direction 'right))
|
||||
((memq direction '(bottom down))
|
||||
(setq direction 'below))
|
||||
(t
|
||||
(setq direction 'below)))
|
||||
|
||||
(setq alist
|
||||
(append alist
|
||||
`(,(if temp-buffer-resize-mode
|
||||
'(window-height . resize-temp-buffer-window)
|
||||
'(window-height . fit-window-to-buffer))
|
||||
,(when temp-buffer-resize-mode
|
||||
'(preserve-size . (nil . t))))))
|
||||
|
||||
(setq windows (windows-sharing-edge window direction within))
|
||||
(dolist (other windows)
|
||||
(cond
|
||||
((and (not other-window-shows-buffer)
|
||||
(eq buffer (window-buffer other)))
|
||||
(setq other-window-shows-buffer t)
|
||||
(setq other-window other))
|
||||
((not other-window)
|
||||
(setq other-window other))))
|
||||
(or (and other-window-shows-buffer
|
||||
(window--display-buffer buffer other-window 'reuse alist))
|
||||
(and (setq other-window
|
||||
(window--try-to-split-window-in-direction
|
||||
window direction alist))
|
||||
(window--display-buffer buffer other-window 'window alist))
|
||||
(and (setq window other-window)
|
||||
(not (window-dedicated-p other-window))
|
||||
(not (window-minibuffer-p other-window))
|
||||
(window--display-buffer buffer other-window 'reuse alist)))))))
|
||||
|
||||
;; This should be rewritten as
|
||||
;; (display-buffer-in-direction buffer (cons '(direction . below) alist))
|
||||
(defun display-buffer-below-selected (buffer alist)
|
||||
"Try displaying BUFFER in a window below the selected window.
|
||||
If there is a window below the selected one and that window
|
||||
|
|
@ -7589,6 +7735,8 @@ must also contain a 'window-height' entry with the same value."
|
|||
(display-buffer--maybe-pop-up-frame buffer alist)
|
||||
(display-buffer-at-bottom buffer alist))))
|
||||
|
||||
;; This should be rewritten as
|
||||
;; (display-buffer-in-direction buffer (cons '(direction . bottom) alist))
|
||||
(defun display-buffer-at-bottom (buffer alist)
|
||||
"Try displaying BUFFER in a window at the bottom of the selected frame.
|
||||
This either reuses such a window provided it shows BUFFER
|
||||
|
|
|
|||
Loading…
Reference in a new issue