Subject: Re: bug#20189: 25.0.50; Feature request: Alternative split-window-sensibly functions

From: martin rudalics <[email-masked]>
Date: Thu, 26 Mar 2015 11:58:17 +0100

>> If you set `split-width-threshold' to zero and
 >> `split-height-threshold' to nil you should get the behavior you want.
 >
 > Wouldn't that mean that I get as many horizontal windows until they
 > become smaller than `window-min-width'?  I want them to alway be at
 > least 80 columns wide.

Then you have to set `split-width-threshold' to a larger value.

 >> You should be able to simplify your code by using idioms from the
 >> below.
 >>
 >> (defun th/split-window-sensibly (_window)
 >>    (let ((root (frame-root-window))
 >> 	(window-combination-resize 'resize))
 >>      (cond
 >>       ((>= (/ (window-total-width root) (window-combinations root t)) 80)
 >>        (split-window (window-last-child root) nil 'right))
 >>       ((>= (/ (window-total-height root) (window-combinations root)) 40)
 >>        (split-window (window-last-child root) nil 'below))
 >>       (t
 >>        (split-window-sensibly window)))))
 >
 > With that and repeated `display-buffer' calls for different buffers
 > starting with a single 269x82 window, I get 3 balanced side-by-side
 > windows first (good!), but the next d-b creates another horizontal
 > window.  Then I have 4 side-by-side balanced windows where each one is
 > less than 80 columns wide.  And yet another d-b splits the rightmost
 > window vertically although I don't want vertical splits at all if there
 > are already horizontal splits.

I only suggested to use the idioms of that form.  Instead of
`window-tree' or `balance-windows' as you did.

 > In that case, it should have reused some
 > existing window.

That's invalid with `split-window-preferred-function':

   This function is called with a window as single argument and is
   supposed to split that window and return the new window.  If the
   window can (or shall) not be split, it is supposed to return nil.

I think its doc-string is very clear about this.

 > That's ok for me although I think I'd like it better if it was this way:
 >
 >   +--------------------+--------------------+-----------------+
 >   |                    |                    |                 |
 >   |                    |                    |                 |
 >   |                    |                    |                 |
 >   |                    |                    |                 |
 >   |                    |                    |                 |
 >   |                    |                    |                 |
 >   |                    |                    |                 |
 >   |                    |                    |                 |
 >   |                    |                    |                 |
 >   |                    |                    |                 |
 >   |                    |                    |   (TWO)         |
 >   |                    |                    |   (THREE)       |
 >   |    *scratch*       |     ONE            |    FOUR         |
 >   +--------------------+--------------------+-----------------+

If you want to "reuse" a window you have to do it "elsewhere".  For
example thusly (largely untested, you also have to tweak hardcoded
values like 40 and 80):

(defun th/display-buffer (buffer alist)
   (or (display-buffer-reuse-window buffer alist)
       (let* ((root (frame-root-window))
	     (horizontal (window-combination-p root t))
	     (combs (window-combinations root horizontal)))
	(if (> combs 1)
	    (let* ((last (window-last-child root))
		   (window-combination-resize 'resize)
		   (window
		    (or (and horizontal
			     (>= (/ (window-total-width root) combs) 80)
			     (split-window last nil 'right))
			(and (not horizontal)
			     (>= (/ (window-total-height root) combs) 40)
			     (split-window last nil 'below)))))
	      (if (window-live-p window)
		  (window--display-buffer
		   buffer window 'window alist display-buffer-mark-dedicated)
		;; Reuse last.
		(window--display-buffer buffer last 'reuse alist)))
	  ;; Try to pop up a new window.
	  (display-buffer-pop-up-window buffer alist)))))

(customize-set-variable
  'display-buffer-base-action '(th/display-buffer . nil))

I hope you get the idea ;-)

martin