Prioritize split along the longest edge by default.

Currently, `split-window-sensibly' prefers to try to split
vertically first, disregarding the actual shape of the frame
or the user preferences.  This is a good default when Emacs
is taller than wider.  However, when Emacs is in full-screen
(landscape screen layout), trying to split vertically may not
be what the user expected, since there is plenty of space
available on the right.

Typical scenario: Emacs is in landscape layout, one buffer is
open in a window covering the entire frame.  Another buffer is
opened in a second window (C-x 4 f). Both splits are feasible
but users may prefer the horizontal one.

This patch preserves the behavior of the `split-height-threshold'
and `split-width-threshold' variables.  Splitting continues not
to be permitted if the edge length is below the threshold.

* lisp/window.el (split-window-sensibly): First tried split
direction follows user preferences.

* etc/NEWS: Add an entry for new variable
`split-window-preferred-direction'.
* doc/emacs/windows.texi: Document new variable.
This commit is contained in:
Nicolas Despres 2024-12-21 12:45:12 +01:00 committed by Eli Zaretskii
parent 028913c446
commit 77ff0df588
3 changed files with 78 additions and 25 deletions

View file

@ -511,6 +511,7 @@ selected frame, and display the buffer in that new window.
@vindex split-height-threshold
@vindex split-width-threshold
@vindex split-window-preferred-direction
The split can be either vertical or horizontal, depending on the
variables @code{split-height-threshold} and
@code{split-width-threshold}. These variables should have integer
@ -519,7 +520,9 @@ window's height, the split puts the new window below. Otherwise, if
@code{split-width-threshold} is smaller than the window's width, the
split puts the new window on the right. If neither condition holds,
Emacs tries to split so that the new window is below---but only if the
window was not split before (to avoid excessive splitting).
window was not split before (to avoid excessive splitting). Whether
Emacs tries first to split vertically or horizontally, is
determined by the value of @code{split-window-preferred-direction}.
@item
Otherwise, display the buffer in a window previously showing it.

View file

@ -226,6 +226,14 @@ It has been obsolete since Emacs 30.1. Use '(category . comint)' instead.
Another user option 'display-tex-shell-buffer-action' has been removed too
for which you can use '(category . tex-shell)'.
+++
*** New user option 'split-window-preferred-direction'.
Users can now choose in which direction Emacs tries to split first:
vertical or horizontal. With this new setting, when the frame is in
landscape shape for instance, Emacs could split horizontally before
splitting vertically. The default setting preserves Emacs historical
behavior to try to split vertically first.
** Frames
+++

View file

@ -7394,20 +7394,64 @@ hold:
(* 2 (max window-min-height
(if mode-line-format 2 1))))))))))
(defcustom split-window-preferred-direction 'vertical
"The first direction tried when Emacs needs to split a window.
This variable controls in which order `split-window-sensibly' will try to
split the window. That order specially matters when both dimensions of
the frame are long enough to be split according to
`split-width-threshold' and `split-height-threshold'. If this is set to
`vertical' (the default), `split-window-sensibly' tries to split
vertically first and then horizontally. If set to `horizontal' it does
the opposite. If set to `longest', the first direction tried
depends on the frame shape: in landscape orientation it will be like
`horizontal', but in portrait it will be like `vertical'. Basically,
the longest of the two dimension is split first.
If both `split-width-threshold' and `split-height-threshold' cannot be
satisfied, it will fallback to split vertically.
See `split-window-preferred-function' for more control of the splitting
strategy."
:type '(radio
(const :tag "Try to split vertically first"
vertical)
(const :tag "Try to split horizontally first"
horizontal)
(const :tag "Try to split along the longest edge first"
longest))
:version "31.1"
:group 'windows)
(defun window--try-vertical-split (window)
"Helper function for `split-window-sensibly'"
(when (window-splittable-p window)
(with-selected-window window
(split-window-below))))
(defun window--try-horizontal-split (window)
"Helper function for `split-window-sensibly'"
(when (window-splittable-p window t)
(with-selected-window window
(split-window-right))))
(defun split-window-sensibly (&optional window)
"Split WINDOW in a way suitable for `display-buffer'.
WINDOW defaults to the currently selected window.
If `split-height-threshold' specifies an integer, WINDOW is at
least `split-height-threshold' lines tall and can be split
vertically, split WINDOW into two windows one above the other and
return the lower window. Otherwise, if `split-width-threshold'
specifies an integer, WINDOW is at least `split-width-threshold'
columns wide and can be split horizontally, split WINDOW into two
windows side by side and return the window on the right. If this
can't be done either and WINDOW is the only window on its frame,
try to split WINDOW vertically disregarding any value specified
by `split-height-threshold'. If that succeeds, return the lower
window. Return nil otherwise.
The variable `split-window-preferred-direction' prescribes an order of
directions in which Emacs should try to split WINDOW. If that order
mandates starting with a vertical split, and `split-height-threshold'
specifies an integer that is at least as large a WINDOW's height, split
WINDOW into two windows one below the other and return the lower one.
If that order mandates starting with a horizontal split, and
`split-width-threshold' specifies an integer that is at least as large
as WINDOW's width, split WINDOW into two windows side by side and return
the one on the right.
In either case, if the first attempt to split WINDOW fails, try to split
the window in the other direction in the same manner as described above.
If that attempt fails too, and WINDOW is the only window on its frame,
try splitting WINDOW into two windows, one below the other, disregarding
the value of `split-height-threshold' and return the window on the
bottom.
By default `display-buffer' routines call this function to split
the largest or least recently used window. To change the default
@ -7427,14 +7471,14 @@ Have a look at the function `window-splittable-p' if you want to
know how `split-window-sensibly' determines whether WINDOW can be
split."
(let ((window (or window (selected-window))))
(or (and (window-splittable-p window)
;; Split window vertically.
(with-selected-window window
(split-window-below)))
(and (window-splittable-p window t)
;; Split window horizontally.
(with-selected-window window
(split-window-right)))
(or (if (or
(eql split-window-preferred-direction 'horizontal)
(and (eql split-window-preferred-direction 'longest)
(> (frame-width) (frame-height))))
(or (window--try-horizontal-split window)
(window--try-vertical-split window))
(or (window--try-vertical-split window)
(window--try-horizontal-split window)))
(and
;; If WINDOW is the only usable window on its frame (it is
;; the only one or, not being the only one, all the other
@ -7452,10 +7496,8 @@ split."
frame nil 'nomini)
t)))
(not (window-minibuffer-p window))
(let ((split-height-threshold 0))
(when (window-splittable-p window)
(with-selected-window window
(split-window-below))))))))
(let ((split-height-threshold 0))
(window--try-vertical-split window))))))
(defun window--try-to-split-window (window &optional alist)
"Try to split WINDOW.