aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-06-20 10:51:51 -0400
committerCraig Jennings <c@cjennings.net>2026-06-20 10:51:51 -0400
commit9e069a310d14f9b6ebbe6e3747240e7844d9ffcb (patch)
tree7b7e0d0ef064342d52442f0ac88b1fc8ed45ab96
parent1020474986be7602aee5673d278586be2b750839 (diff)
downloaddotemacs-9e069a310d14f9b6ebbe6e3747240e7844d9ffcb.tar.gz
dotemacs-9e069a310d14f9b6ebbe6e3747240e7844d9ffcb.zip
fix(windows): keep the pulled-away window on the arrow's edge
The sole-window pull split toward the arrow at 50/50, so a fullscreen terminal jumped above the revealed buffer at half height. Now the reveal opens on the opposite side and is minimized to a sliver, so the current window keeps the arrow's edge near-full and the sticky windsize arrows shrink it step by step, matching the feel of resizing an existing split.
-rw-r--r--modules/ui-navigation.el46
-rw-r--r--tests/test-ui-navigation--window-resize.el34
2 files changed, 45 insertions, 35 deletions
diff --git a/modules/ui-navigation.el b/modules/ui-navigation.el
index 00fa841e1..f53924ebb 100644
--- a/modules/ui-navigation.el
+++ b/modules/ui-navigation.el
@@ -75,26 +75,31 @@ resize -- each moves the active window's divider in the arrow's direction
"<up>" #'windsize-up
"<down>" #'windsize-down)
-(defun cj/window-arrow-direction (key)
- "Map a windsize arrow KEY description to a split direction.
-KEY is one of \"<left>\" \"<right>\" \"<up>\" \"<down>\"; returns
-left/right/above/below respectively, or nil for anything else."
+(defun cj/window-pull-side (key)
+ "Map a `C-; b' arrow KEY to the side the revealed window opens on.
+The arrow names the edge the current window shrinks toward, so the new
+window opens on the *opposite* side and the current window keeps the
+arrow's edge: <down> -> above, <up> -> below, <left> -> right,
+<right> -> left. Returns nil for anything else."
(pcase key
- ("<left>" 'left)
- ("<right>" 'right)
- ("<up>" 'above)
- ("<down>" 'below)
+ ("<down>" 'above)
+ ("<up>" 'below)
+ ("<left>" 'right)
+ ("<right>" 'left)
(_ nil)))
-(defun cj/window--pull-away (direction)
- "Split the sole window toward DIRECTION and reveal the previous buffer.
-DIRECTION is one of left/right/above/below. A new window opens on that
-side showing `other-buffer'; focus stays on the original window so it
-shrinks from that edge, letting a fullscreen window (e.g. a terminal)
-share the frame. No-op when DIRECTION is nil."
- (when direction
- (let ((new (split-window (selected-window) nil direction)))
+(defun cj/window--pull-away (side)
+ "Split the sole window so the previous buffer opens on SIDE.
+SIDE is one of above/below/left/right -- opposite the pressed arrow, so
+the current window keeps the arrow's edge. The new window is minimized
+to a sliver (the current window keeps almost the whole frame) and shows
+`other-buffer'; focus stays on the current window so the sticky arrows
+then shrink it step by step via `windsize', exactly as resizing an
+existing split does. No-op when SIDE is nil."
+ (when side
+ (let ((new (split-window (selected-window) nil side)))
(set-window-buffer new (other-buffer (current-buffer) t))
+ (minimize-window new)
new)))
(defun cj/window-resize-sticky ()
@@ -103,12 +108,15 @@ share the frame. No-op when DIRECTION is nil."
nudging until any other key. Bound to `C-; b <left>/<right>/<up>/<down>'.
When the selected window is the sole window in the frame there is no
-divider to move, so the arrow instead pulls a new window away toward that
-edge (`cj/window--pull-away'), revealing the previous buffer."
+divider to move, so the first arrow instead splits a sliver away on the
+side opposite the arrow (`cj/window--pull-away'), revealing the previous
+buffer; the current window keeps almost the whole frame and the following
+arrows shrink it via `windsize', so it reads the same as resizing an
+existing split."
(interactive)
(let ((key (key-description (vector last-command-event))))
(if (one-window-p)
- (cj/window--pull-away (cj/window-arrow-direction key))
+ (cj/window--pull-away (cj/window-pull-side key))
(let ((cmd (keymap-lookup cj/window-resize-map key)))
(when cmd (call-interactively cmd)))))
(set-transient-map cj/window-resize-map t))
diff --git a/tests/test-ui-navigation--window-resize.el b/tests/test-ui-navigation--window-resize.el
index 986ce1580..553219755 100644
--- a/tests/test-ui-navigation--window-resize.el
+++ b/tests/test-ui-navigation--window-resize.el
@@ -44,24 +44,26 @@ otherwise route to the pull-away path."
(should ran) ; dispatched to the right command
(should overriding-terminal-local-map)))) ; loop armed
-(ert-deftest test-ui-navigation-window-arrow-direction ()
- "Normal/Error: each arrow maps to its split direction; anything else is nil."
- (should (eq (cj/window-arrow-direction "<left>") 'left))
- (should (eq (cj/window-arrow-direction "<right>") 'right))
- (should (eq (cj/window-arrow-direction "<up>") 'above))
- (should (eq (cj/window-arrow-direction "<down>") 'below))
- (should (null (cj/window-arrow-direction "<prior>")))
- (should (null (cj/window-arrow-direction "x"))))
+(ert-deftest test-ui-navigation-window-pull-side ()
+ "Normal/Error: each arrow maps to the *opposite* side (where the revealed
+window opens, so the current window keeps the arrow's edge); anything else
+is nil."
+ (should (eq (cj/window-pull-side "<down>") 'above))
+ (should (eq (cj/window-pull-side "<up>") 'below))
+ (should (eq (cj/window-pull-side "<left>") 'right))
+ (should (eq (cj/window-pull-side "<right>") 'left))
+ (should (null (cj/window-pull-side "<prior>")))
+ (should (null (cj/window-pull-side "x"))))
(ert-deftest test-ui-navigation-window-resize-sticky-sole-window-pulls-away ()
- "Normal: with a single window, the arrow pulls a window away toward its
-direction (via `cj/window--pull-away') rather than resizing, then arms the
-loop. `cj/window--pull-away' is stubbed to capture the direction so no real
-window split happens under `--batch'."
- (dolist (case '((left . left)
- (right . right)
- (up . above)
- (down . below)))
+ "Normal: with a single window, the arrow pulls a sliver away on the side
+opposite the arrow (via `cj/window--pull-away') rather than resizing, then
+arms the loop. `cj/window--pull-away' is stubbed to capture the side so no
+real window split happens under `--batch'."
+ (dolist (case '((down . above)
+ (up . below)
+ (left . right)
+ (right . left)))
(let ((pulled nil)
(overriding-terminal-local-map nil)
(pre-command-hook nil))