131 lines
5.5 KiB
EmacsLisp
131 lines
5.5 KiB
EmacsLisp
;;; +window.el --- Fixes for Emacs's window.el -*- lexical-binding: t; -*-
|
|
|
|
;;; Commentary:
|
|
|
|
;; Do I want to propose this change in the Emacs ML?
|
|
|
|
;;; Code:
|
|
|
|
(require 'window)
|
|
|
|
;;; Split windows based on `window-total-width', not `window-width'
|
|
;; I have to just redefine these functions because the check is really deep in
|
|
;; there.
|
|
|
|
(defun window-splittable-p (window &optional horizontal)
|
|
"Return non-nil if `split-window-sensibly' may split WINDOW.
|
|
Optional argument HORIZONTAL nil or omitted means check whether
|
|
`split-window-sensibly' may split WINDOW vertically. HORIZONTAL
|
|
non-nil means check whether WINDOW may be split horizontally.
|
|
|
|
WINDOW may be split vertically when the following conditions
|
|
hold:
|
|
- `window-size-fixed' is either nil or equals `width' for the
|
|
buffer of WINDOW.
|
|
- `split-height-threshold' is an integer and WINDOW is at least as
|
|
high as `split-height-threshold'.
|
|
- When WINDOW is split evenly, the emanating windows are at least
|
|
`window-min-height' lines tall and can accommodate at least one
|
|
line plus - if WINDOW has one - a mode line.
|
|
|
|
WINDOW may be split horizontally when the following conditions
|
|
hold:
|
|
- `window-size-fixed' is either nil or equals `height' for the
|
|
buffer of WINDOW.
|
|
- `split-width-threshold' is an integer and WINDOW is at least as
|
|
wide as `split-width-threshold'.
|
|
- When WINDOW is split evenly, the emanating windows are at least
|
|
`window-min-width' or two (whichever is larger) columns wide."
|
|
(when (and (window-live-p window)
|
|
(not (window-parameter window 'window-side)))
|
|
(with-current-buffer (window-buffer window)
|
|
(if horizontal
|
|
;; A window can be split horizontally when its width is not
|
|
;; fixed, it is at least `split-width-threshold' columns wide
|
|
;; and at least twice as wide as `window-min-width' and 2 (the
|
|
;; latter value is hardcoded).
|
|
(and (memq window-size-fixed '(nil height))
|
|
;; Testing `window-full-width-p' here hardly makes any
|
|
;; sense nowadays. This can be done more intuitively by
|
|
;; setting up `split-width-threshold' appropriately.
|
|
(numberp split-width-threshold)
|
|
(>= (window-total-width window)
|
|
(max split-width-threshold
|
|
(* 2 (max window-min-width 2)))))
|
|
;; A window can be split vertically when its height is not
|
|
;; fixed, it is at least `split-height-threshold' lines high,
|
|
;; and it is at least twice as high as `window-min-height' and 2
|
|
;; if it has a mode line or 1.
|
|
(and (memq window-size-fixed '(nil width))
|
|
(numberp split-height-threshold)
|
|
(>= (window-height window)
|
|
(max split-height-threshold
|
|
(* 2 (max window-min-height
|
|
(if mode-line-format 2 1))))))))))
|
|
|
|
(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.
|
|
|
|
By default `display-buffer' routines call this function to split
|
|
the largest or least recently used window. To change the default
|
|
customize the option `split-window-preferred-function'.
|
|
|
|
You can enforce this function to not split WINDOW horizontally,
|
|
by setting (or binding) the variable `split-width-threshold' to
|
|
nil. If, in addition, you set `split-height-threshold' to zero,
|
|
chances increase that this function does split WINDOW vertically.
|
|
|
|
In order to not split WINDOW vertically, set (or bind) the
|
|
variable `split-height-threshold' to nil. Additionally, you can
|
|
set `split-width-threshold' to zero to make a horizontal split
|
|
more likely to occur.
|
|
|
|
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)))
|
|
(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'.
|
|
(let ((frame (window-frame window)))
|
|
(or
|
|
(eq window (frame-root-window frame))
|
|
(catch 'done
|
|
(walk-window-tree (lambda (w)
|
|
(unless (or (eq w window)
|
|
(window-dedicated-p w))
|
|
(throw 'done nil)))
|
|
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))))))))
|
|
|
|
(provide '+window)
|
|
;;; +window.el ends here
|