diff options
| author | Martin Rudalics | 2019-05-19 11:03:05 +0200 |
|---|---|---|
| committer | Martin Rudalics | 2019-05-19 11:03:05 +0200 |
| commit | 8783becbba410581c6384ee021e7e83ad5236a29 (patch) | |
| tree | 96cb1f85d83a836f9823acac0e16a89b7a0d9769 /lisp | |
| parent | b87e5eea1dd7c7345d0a9f82759eedfd7c9a8099 (diff) | |
| download | emacs-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.
Diffstat (limited to 'lisp')
| -rw-r--r-- | lisp/window.el | 148 |
1 files changed, 148 insertions, 0 deletions
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. | ||
| 7539 | WINDOW must be a valid window and defaults to the selected one. | ||
| 7540 | EDGE 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 | |||
| 7544 | WITHIN nil means to find a live window that shares the opposite | ||
| 7545 | EDGE with WINDOW. For example, if EDGE equals 'left', WINDOW has | ||
| 7546 | to share (part of) the right edge of any window returned. WITHIN | ||
| 7547 | non-nil means to find all live windows that share the same EDGE | ||
| 7548 | with WINDOW (Window must be internal in this case). So if EDGE | ||
| 7549 | equals 'left', WINDOW's left edge has to fully encompass the left | ||
| 7550 | edge 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. | ||
| 7583 | DIRECTION is passed as SIDE argument to `split-window-no-error'. | ||
| 7584 | ALIST 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. | ||
| 7603 | ALIST has to contain a 'direction' entry whose value should be | ||
| 7604 | one of 'left', 'above' (or 'up'), 'right', and 'below' (or | ||
| 7605 | 'down'). Other values are usually interpreted as 'below'. | ||
| 7606 | |||
| 7607 | If ALIST also contains a 'window' entry, its value specifies a | ||
| 7608 | reference 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 | ||
| 7611 | arbitrary valid window. Any other value (or omitting the | ||
| 7612 | 'window' entry) means to use the selected window as reference | ||
| 7613 | window. | ||
| 7614 | |||
| 7615 | This function tries to reuse or split a window such that the | ||
| 7616 | window produced this way is on the side of the reference window | ||
| 7617 | specified by the 'direction' entry. | ||
| 7618 | |||
| 7619 | Four special values for 'direction' entries allow to implicitly | ||
| 7620 | specify 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. |
| 7539 | If there is a window below the selected one and that window | 7685 | 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." | |||
| 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. |
| 7594 | This either reuses such a window provided it shows BUFFER | 7742 | This either reuses such a window provided it shows BUFFER |