From 8d94a9ec613470b7e8e4ee0e86b643f34f8a724c Mon Sep 17 00:00:00 2001
From: Nicolas Despres <nicolas.despres@gmail.com>
Date: Fri, 13 Dec 2024 19:58:13 +0100
Subject: [PATCH] Split along the longest edge by default.

Currently, `split-window-sensibly' prefer to split vertically
disregarding the actual shape of the frame.  This is a good default when
Emacs is taller than wider.  However, when Emacs is in fullscreen
(landscape screen layout) splitting vertically is generally not the
things to do because there is plenty more space on the right.

Typical scenario: Emacs is in fullscreen, one buffer is open in window
covering the entire frame.  Another buffer is opened in a second
window (C-x 4 f). In this case, the split should happen horizontally.

I have tested this approach since a couple of weeks now and it works well
if `split-height-threshold' and `split-width-threshold' are set
properly.

* lisp/window.el (split-window-sensibly): Always prefer the longest edge
instead of blindly splitting vertically, unless width is less than 80 columns.

A part from that, the patch carefully preserves the current split logic.
---
 lisp/window.el | 68 ++++++++++++++++++++++++++++++--------------------
 1 file changed, 41 insertions(+), 27 deletions(-)

diff --git a/lisp/window.el b/lisp/window.el
index e9d57652ec6..58ca6c8679d 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -7347,20 +7347,30 @@ window-splittable-p
 		      (* 2 (max window-min-height
 				(if mode-line-format 2 1))))))))))
 
+(defun window--try-split-window-vertically (window)
+  "Helper function for `split-window-sensibly'"
+  (when (window-splittable-p window)
+    (with-selected-window window
+      (split-window-below))))
+
+(defun window--try-split-window-horizontally (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.
+WINDOW defaults to the currently selected window.  First, try to split
+along the longest edge of the window.  If the threshold
+(`split-height-threshold' respectively `split-width-threshold')
+specifies an integer, WINDOW is at least that threshold lines tall
+(resp. wide) and can be split (vertically respectively horizontally).
+If that fails, try to split along the shortest edge.  If this can't be
+done either and WINDOW is the only window on its frame, try to split
+WINDOW along the longest edge disregarding any value specified by
+`split-height-threshold' respectively `split-width-threshold'. If that
+succeeds, return the lower window.  Return nil otherwise.
 
 By default `display-buffer' routines call this function to split
 the largest or least recently used window.  To change the default
@@ -7379,21 +7389,27 @@ split-window-sensibly
 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)))
+  (let ((window (or window (selected-window)))
+        (first-split nil)
+        (second-split nil)
+        (first-threshold-variable nil))
+    ;; Choose preferred splitting edge.
+    (if (and (> (frame-width) (frame-height)) (> (frame-width) 80))
+        (setq first-split 'window--try-split-window-horizontally
+              second-split 'window--try-split-window-vertically
+              first-threshold-variable 'split-width-threshold)
+      (setq first-split 'window--try-split-window-vertically
+            second-split 'window--try-split-window-horizontally
+            first-threshold-variable 'split-height-threshold))
+    (or (funcall first-split window)
+	(funcall second-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
          ;; ones are dedicated) and is not the minibuffer window, try
-         ;; to split it vertically disregarding the value of
-         ;; `split-height-threshold'.
+         ;; to split it along the longest edge disregarding the value of
+         ;; the matching threshold (`split-height-threshold'
+         ;; or `split-width-threshold').
          (let ((frame (window-frame window)))
            (or
             (eq window (frame-root-window frame))
@@ -7405,10 +7421,8 @@ split-window-sensibly
                                 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))))))))
+	 (eval `(let ((,first-threshold-variable 0))
+                  (funcall first-split window)))))))
 
 (defun window--try-to-split-window (window &optional alist)
   "Try to split WINDOW.
-- 
2.47.1

