aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Rudalics2019-05-19 11:03:05 +0200
committerMartin Rudalics2019-05-19 11:03:05 +0200
commit8783becbba410581c6384ee021e7e83ad5236a29 (patch)
tree96cb1f85d83a836f9823acac0e16a89b7a0d9769
parentb87e5eea1dd7c7345d0a9f82759eedfd7c9a8099 (diff)
downloademacs-8783becbba410581c6384ee021e7e83ad5236a29.tar.gz
emacs-8783becbba410581c6384ee021e7e83ad5236a29.zip
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.
-rw-r--r--doc/lispref/windows.texi67
-rw-r--r--etc/NEWS15
-rw-r--r--lisp/window.el148
3 files changed, 229 insertions, 1 deletions
diff --git a/doc/lispref/windows.texi b/doc/lispref/windows.texi
index 32e8c2afa31..96e42a148c5 100644
--- a/doc/lispref/windows.texi
+++ b/doc/lispref/windows.texi
@@ -2601,6 +2601,63 @@ window and displaying the buffer in that window. It can fail if all
2601windows are dedicated to other buffers (@pxref{Dedicated Windows}). 2601windows are dedicated to other buffers (@pxref{Dedicated Windows}).
2602@end defun 2602@end defun
2603 2603
2604@defun display-buffer-in-direction buffer alist
2605This function tries to display @var{buffer} at a location specified by
2606@var{alist}. For this purpose, @var{alist} should contain a
2607@code{direction} entry whose value is one of @code{left}, @code{above}
2608(or @code{up}), @code{right} and @code{below} (or @code{down}). Other
2609values are usually interpreted as @code{below}.
2610
2611If @var{alist} also contains a @code{window} entry, its value
2612specifies a reference window. That value can be a special symbol like
2613@code{main} which stands for the selected frame's main window
2614(@pxref{Side Window Options and Functions}) or @code{root} standing
2615for the selected frame's root window (@pxref{Windows and Frames}). It
2616can also specify an arbitrary valid window. Any other value (or
2617omitting the @code{window} entry entirely) means to use the selected
2618window as reference window.
2619
2620This function first tries to reuse a window in the specified direction
2621that already shows @var{buffer}. If no such window exists, it tries
2622to split the reference window in order to produce a new window in the
2623specified direction. If this fails as well, it will try to display
2624@var{buffer} in an existing window in the specified direction. In
2625either case, the window chosen will appear on the side of the
2626reference window specified by the @code{direction} entry, sharing at
2627least one edge with the reference window.
2628
2629If the reference window is live, the edge the chosen window will share
2630with it is always the opposite of the one specified by the
2631@code{direction} entry. For example, if the value of the
2632@code{direction} entry is @code{left}, the chosen window's right edge
2633coordinate (@pxref{Coordinates and Windows}) will equal the reference
2634window's left edge coordinate.
2635
2636If the reference window is internal, a reused window must share with
2637it the edge specified by the @code{direction} entry. Hence if, for
2638example, the reference window is the frame's root window and the value
2639of the @code{direction} entry is @code{left}, a reused window must be
2640on the left of the frame. This means that the left edge coordinate of
2641the chosen window and that of the reference window are the same.
2642
2643A new window, however, will be created by splitting the reference
2644window such that the chosen window will share the opposite edge with
2645the reference window. In our example, a new root window would be
2646created with a new live window and the reference window as its
2647children. The chosen window's right edge coordinate would then equal
2648the left edge coordinate of the reference window. Its left edge
2649coordinate would equal the left edge coordinate of the frame's new
2650root window.
2651
2652Four special values for @code{direction} entries allow to implicitly
2653specify the selected frame's main window as the reference window:
2654@code{leftmost}, @code{top}, @code{rightmost} and @code{bottom}. This
2655means that instead of, for example, @w{@code{(direction . left)
2656(window . main)}} one can just specify @w{@code{(direction
2657. leftmost)}}. An existing @code{window} @var{alist} entry is ignored
2658in such cases.
2659@end defun
2660
2604@defun display-buffer-below-selected buffer alist 2661@defun display-buffer-below-selected buffer alist
2605This function tries to display @var{buffer} in a window below the 2662This function tries to display @var{buffer} in a window below the
2606selected window. If there is a window below the selected one and that 2663selected 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
2934supposed to display the buffer. This entry is used only by 2991supposed to display the buffer. This entry is used only by
2935@code{display-buffer-in-side-window}. 2992@code{display-buffer-in-side-window}.
2936 2993
2994@vindex direction@r{, a buffer display action alist entry}
2995@item direction
2996The value specifies a direction which, together with a @code{window}
2997entry, allows @code{display-buffer-in-direction} to determine the
2998location of the window to display the buffer.
2999
2937@vindex window@r{, a buffer display action alist entry} 3000@vindex window@r{, a buffer display action alist entry}
2938@item window 3001@item window
2939The value specifies a window that is in some way related to the window 3002The value specifies a window that is in some way related to the window
2940chosen by @code{display-buffer}. This entry is currently used by 3003chosen by @code{display-buffer}. This entry is currently used by
2941@code{display-buffer-in-atom-window} to indicate the window on whose 3004@code{display-buffer-in-atom-window} to indicate the window on whose
2942side the new window shall be created. 3005side the new window shall be created. It is also used by
3006@code{display-buffer-in-direction} to specify the reference window on
3007whose side the resulting window shall appear.
2943 3008
2944@vindex allow-no-window@r{, a buffer display action alist entry} 3009@vindex allow-no-window@r{, a buffer display action alist entry}
2945@item allow-no-window 3010@item allow-no-window
diff --git a/etc/NEWS b/etc/NEWS
index b4aa8d98ffa..d70cda179e0 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1779,6 +1779,11 @@ This option allows to automatically resize minibuffer-only frames
1779similarly to how minibuffer windows are resized on "normal" frames. 1779similarly to how minibuffer windows are resized on "normal" frames.
1780 1780
1781+++ 1781+++
1782** New buffer display action function 'display-buffer-in-direction'.
1783This function allows to specify the location of the window chosen by
1784'display-buffer' in various ways.
1785
1786+++
1782** New buffer display action alist entry 'dedicated'. 1787** New buffer display action alist entry 'dedicated'.
1783Such an entry allows to specify the dedicated status of a window 1788Such an entry allows to specify the dedicated status of a window
1784created by 'display-buffer'. 1789created by 'display-buffer'.
@@ -1790,6 +1795,16 @@ for displaying a buffer. 'display-buffer-below-selected' is the only
1790action function to respect it at the moment. 1795action function to respect it at the moment.
1791 1796
1792+++ 1797+++
1798** New buffer display action alist entry 'direction'.
1799This entry is used to specify the location of the window chosen by
1800'display-buffer-in-direction'.
1801
1802+++
1803** Additional meaning of display action alist entry 'window'.
1804A 'window' entry can now also specify a reference window for
1805'display-buffer-in-direction'.
1806
1807+++
1793** The function 'assoc-delete-all' now takes an optional predicate argument. 1808** The function 'assoc-delete-all' now takes an optional predicate argument.
1794 1809
1795+++ 1810+++
diff --git a/lisp/window.el b/lisp/window.el
index b4f5ac5cc44..2c9d177d0a2 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -7534,6 +7534,152 @@ be added to ALIST."
7534 (unless (cdr (assq 'inhibit-switch-frame alist)) 7534 (unless (cdr (assq 'inhibit-switch-frame alist))
7535 (window--maybe-raise-frame frame))))) 7535 (window--maybe-raise-frame frame)))))
7536 7536
7537(defun windows-sharing-edge (&optional window edge within)
7538 "Return list of live windows sharing the same edge with WINDOW.
7539WINDOW must be a valid window and defaults to the selected one.
7540EDGE stands for the edge to share and must be either 'left',
7541'above', 'right' or 'below'. Omitted or nil, EDGE defaults to
7542'left'.
7543
7544WITHIN nil means to find a live window that shares the opposite
7545EDGE with WINDOW. For example, if EDGE equals 'left', WINDOW has
7546to share (part of) the right edge of any window returned. WITHIN
7547non-nil means to find all live windows that share the same EDGE
7548with WINDOW (Window must be internal in this case). So if EDGE
7549equals 'left', WINDOW's left edge has to fully encompass the left
7550edge of any window returned."
7551 (setq window (window-normalize-window window))
7552 (setq edge (or edge 'left))
7553 (when (and within (window-live-p window))
7554 (error "Cannot share edge from within live window %s" window))
7555 (let ((window-edges (window-edges window nil nil t))
7556 (horizontal (memq edge '(left right)))
7557 (n (pcase edge
7558 ('left 0) ('above 1) ('right 2) ('below 3))))
7559 (unless (numberp n)
7560 (error "Invalid EDGE %s" edge))
7561 (let ((o (mod (+ 2 n) 4))
7562 (p (if horizontal 1 0))
7563 (q (if horizontal 3 2))
7564 windows)
7565 (walk-window-tree
7566 (lambda (other)
7567 (let ((other-edges (window-edges other nil nil t)))
7568 (when (and (not (eq window other))
7569 (= (nth n window-edges)
7570 (nth (if within n o) other-edges))
7571 (cond
7572 ((= (nth p window-edges) (nth p other-edges)))
7573 ((< (nth p window-edges) (nth p other-edges))
7574 (< (nth p other-edges) (nth q window-edges)))
7575 (t
7576 (< (nth p window-edges) (nth q other-edges)))))
7577 (setq windows (cons other windows)))))
7578 (window-frame window) nil 'nomini)
7579 (reverse windows))))
7580
7581(defun window--try-to-split-window-in-direction (window direction alist)
7582 "Try to split WINDOW in DIRECTION.
7583DIRECTION is passed as SIDE argument to `split-window-no-error'.
7584ALIST is a buffer display alist."
7585 (and (not (frame-parameter (window-frame window) 'unsplittable))
7586 (let* ((window-combination-limit
7587 ;; When `window-combination-limit' equals
7588 ;; `display-buffer' or equals `resize-window' and a
7589 ;; `window-height' or `window-width' alist entry are
7590 ;; present, bind it to t so resizing steals space
7591 ;; preferably from the window that was split.
7592 (if (or (eq window-combination-limit 'display-buffer)
7593 (and (eq window-combination-limit 'window-size)
7594 (or (cdr (assq 'window-height alist))
7595 (cdr (assq 'window-width alist)))))
7596 t
7597 window-combination-limit))
7598 (new-window (split-window-no-error window nil direction)))
7599 (and (window-live-p new-window) new-window))))
7600
7601(defun display-buffer-in-direction (buffer alist)
7602 "Try to display BUFFER in a direction specified by ALIST.
7603ALIST has to contain a 'direction' entry whose value should be
7604one of 'left', 'above' (or 'up'), 'right', and 'below' (or
7605'down'). Other values are usually interpreted as 'below'.
7606
7607If ALIST also contains a 'window' entry, its value specifies a
7608reference window. That value can be a special symbol like
7609'main' (which stands for the selected frame's main window) or
7610'root' (standings for the selected frame's root window) or an
7611arbitrary valid window. Any other value (or omitting the
7612'window' entry) means to use the selected window as reference
7613window.
7614
7615This function tries to reuse or split a window such that the
7616window produced this way is on the side of the reference window
7617specified by the 'direction' entry.
7618
7619Four special values for 'direction' entries allow to implicitly
7620specify the selected frame's main window as reference window:
7621'leftmost', 'top', 'rightmost' and 'bottom'. Hence, instead of
7622'(direction . left) (window . main)' one can simply write
7623'(direction . leftmost)'."
7624 (let ((direction (cdr (assq 'direction alist))))
7625 (when direction
7626 (let ((window (cdr (assq 'window alist)))
7627 within windows other-window-shows-buffer other-window)
7628 ;; Sanitize WINDOW.
7629 (cond
7630 ((or (eq window 'main)
7631 (memq direction '(top bottom leftmost rightmost)))
7632 (setq window (window-main-window)))
7633 ((eq window 'root)
7634 (setq window (frame-root-window)))
7635 ((window-valid-p window))
7636 (t
7637 (setq window (selected-window))))
7638 (setq within (not (window-live-p window)))
7639 ;; Sanitize DIRECTION
7640 (cond
7641 ((memq direction '(left above right below)))
7642 ((eq direction 'leftmost)
7643 (setq direction 'left))
7644 ((memq direction '(top up))
7645 (setq direction 'above))
7646 ((eq direction 'rightmost)
7647 (setq direction 'right))
7648 ((memq direction '(bottom down))
7649 (setq direction 'below))
7650 (t
7651 (setq direction 'below)))
7652
7653 (setq alist
7654 (append alist
7655 `(,(if temp-buffer-resize-mode
7656 '(window-height . resize-temp-buffer-window)
7657 '(window-height . fit-window-to-buffer))
7658 ,(when temp-buffer-resize-mode
7659 '(preserve-size . (nil . t))))))
7660
7661 (setq windows (windows-sharing-edge window direction within))
7662 (dolist (other windows)
7663 (cond
7664 ((and (not other-window-shows-buffer)
7665 (eq buffer (window-buffer other)))
7666 (setq other-window-shows-buffer t)
7667 (setq other-window other))
7668 ((not other-window)
7669 (setq other-window other))))
7670 (or (and other-window-shows-buffer
7671 (window--display-buffer buffer other-window 'reuse alist))
7672 (and (setq other-window
7673 (window--try-to-split-window-in-direction
7674 window direction alist))
7675 (window--display-buffer buffer other-window 'window alist))
7676 (and (setq window other-window)
7677 (not (window-dedicated-p other-window))
7678 (not (window-minibuffer-p other-window))
7679 (window--display-buffer buffer other-window 'reuse alist)))))))
7680
7681;; This should be rewritten as
7682;; (display-buffer-in-direction buffer (cons '(direction . below) alist))
7537(defun display-buffer-below-selected (buffer alist) 7683(defun display-buffer-below-selected (buffer alist)
7538 "Try displaying BUFFER in a window below the selected window. 7684 "Try displaying BUFFER in a window below the selected window.
7539If there is a window below the selected one and that window 7685If 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."
7589 (display-buffer--maybe-pop-up-frame buffer alist) 7735 (display-buffer--maybe-pop-up-frame buffer alist)
7590 (display-buffer-at-bottom buffer alist)))) 7736 (display-buffer-at-bottom buffer alist))))
7591 7737
7738;; This should be rewritten as
7739;; (display-buffer-in-direction buffer (cons '(direction . bottom) alist))
7592(defun display-buffer-at-bottom (buffer alist) 7740(defun display-buffer-at-bottom (buffer alist)
7593 "Try displaying BUFFER in a window at the bottom of the selected frame. 7741 "Try displaying BUFFER in a window at the bottom of the selected frame.
7594This either reuses such a window provided it shows BUFFER 7742This either reuses such a window provided it shows BUFFER