From: martin rudalics <rudalics@gmx.at>
To: Juri Linkov <juri@linkov.net>
Cc: 35592@debbugs.gnu.org
Subject: bug#35592: Use display-buffer-in-direction for completion-like windows
Date: Wed, 8 May 2019 11:09:50 +0200 [thread overview]
Message-ID: <52083e2f-6320-a39c-feda-352d414f4690@gmx.at> (raw)
In-Reply-To: <8736lq54wf.fsf@mail.linkov.net>
[-- Attachment #1: Type: text/plain, Size: 551 bytes --]
> Only a small plea: could you please add an alias ‘(direction . bottom)’
> as a shorthand for ‘(direction . below) (window . main)’
>
> Similarly:
> top = (direction . above) (window . main)
> bottom = (direction . below) (window . main)
> leftmost = (direction . left) (window . main)
> rightmost = (direction . right) (window . main)
Patch attached. But notice that these semantically clash with what you
earlier wanted for 'split-window':
((eq side 'above) 'top)
((eq side 'below) 'bottom)
martin
[-- Attachment #2: display-buffer-in-direction.diff --]
[-- Type: text/plain, Size: 7268 bytes --]
diff --git a/lisp/window.el b/lisp/window.el
index b4f5ac5cc4..3bbb836108 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -7534,6 +7534,156 @@ display-buffer-in-child-frame
(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 cdr should be one
+of 'left', 'above', 'up', 'right', 'below' or 'down'. Any other
+value is interpreted as 'below'.
+
+If ALIST also contains a 'window' entry, the cdr of that entry
+specifies a reference window. Its value can be a special symbol
+like 'main' (which stands for the selected frame's main window)
+or 'root' (which stands 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.
+
+There are four 'direction' keys with a special meaning: 'top' is
+a shorthand for writing '((direction . above) (window . main))',
+'bottom' stands for '((direction . below) (window . main)))'.
+Also 'leftmost' stands for '((direction . left) (window . main))'
+and 'rightmost' for '((direction . right) (window . main))'. In
+either of these cases any 'window' ALIST entry is ignored.
+
+If the reference window specifies an internal window, try to
+split or reuse a window within the reference window such that the
+window produced this way is on the side of the reference window
+specified by the direction entry. If the reference window
+specifies a live window, try to split that window or reuse a
+window on the side specified by the direction entry."
+ (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 +7739,8 @@ display-buffer--maybe-at-bottom
(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
next prev parent reply other threads:[~2019-05-08 9:09 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-05-05 20:40 bug#35592: Use display-buffer-in-direction for completion-like windows Juri Linkov
2019-05-07 8:14 ` martin rudalics
2019-05-07 21:30 ` Juri Linkov
2019-05-08 9:09 ` martin rudalics [this message]
2019-05-08 19:32 ` Juri Linkov
2019-05-09 8:12 ` martin rudalics
2019-05-09 19:50 ` Juri Linkov
2019-05-10 5:34 ` Eli Zaretskii
2019-05-11 20:48 ` Juri Linkov
2019-05-12 2:31 ` Eli Zaretskii
2019-05-12 19:17 ` Juri Linkov
2019-05-19 9:17 ` martin rudalics
2019-05-19 19:54 ` Juri Linkov
2019-05-20 8:25 ` martin rudalics
2019-05-20 20:36 ` Juri Linkov
2019-05-21 7:32 ` martin rudalics
2019-05-21 20:18 ` Juri Linkov
2019-05-22 8:31 ` martin rudalics
2019-06-05 20:57 ` Juri Linkov
2019-05-19 9:17 ` martin rudalics
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=52083e2f-6320-a39c-feda-352d414f4690@gmx.at \
--to=rudalics@gmx.at \
--cc=35592@debbugs.gnu.org \
--cc=juri@linkov.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this external index
https://git.savannah.gnu.org/cgit/emacs.git
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.