diff options
| author | Craig Jennings <c@cjennings.net> | 2026-06-15 21:54:55 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-06-15 21:54:55 -0500 |
| commit | 60f14d2c1aa5074f23ec5bccfa0d233ec6730bdb (patch) | |
| tree | 6f25f635232f0f9b79877e57090b4ea9eacc0b86 | |
| parent | ea46c4a90c9f2de94cdb6ab4e47e744a9506ee37 (diff) | |
| download | dotemacs-60f14d2c1aa5074f23ec5bccfa0d233ec6730bdb.tar.gz dotemacs-60f14d2c1aa5074f23ec5bccfa0d233ec6730bdb.zip | |
feat(ai-term): dock the agent window by frame aspect ratio
The agent window now docks from whichever edge conserves more space, chosen at display time: right on a landscape frame, bottom on a square or portrait one, replacing the host (laptop/desktop) branch. cj/--ai-term-direction-for-aspect is the pure decision; default-size pairs the width or height fraction with it.
| -rw-r--r-- | modules/ai-term.el | 36 | ||||
| -rw-r--r-- | tests/test-ai-term--default-geometry.el | 55 |
2 files changed, 52 insertions, 39 deletions
diff --git a/modules/ai-term.el b/modules/ai-term.el index baf752fe7..49d44d25e 100644 --- a/modules/ai-term.el +++ b/modules/ai-term.el @@ -391,22 +391,30 @@ fallback when `cj/--ai-term-last-size' is nil." :type 'number :group 'ai-term) -(defun cj/--ai-term-default-direction () - "Return the host-appropriate default split direction for the agent window. - -`below' on a laptop (bottom horizontal split), `right' on a desktop -(right-side vertical split). Detected via `env-laptop-p'." - (if (env-laptop-p) 'below 'right)) +(defun cj/--ai-term-direction-for-aspect (pixel-width pixel-height) + "Return the space-conserving dock direction for a frame of PIXEL-WIDTH by +PIXEL-HEIGHT. `right' when the frame is wider than tall (dock from the right +edge), `below' when it is square or taller (dock from the bottom)." + (if (> pixel-width pixel-height) 'right 'below)) + +(defun cj/--ai-term-default-direction (&optional frame) + "Return the default split direction for the agent window. + +Chosen at display time from FRAME's pixel aspect ratio (FRAME defaults to the +selected frame): `right' on a landscape frame, `below' on a square or portrait +one -- whichever edge conserves more screen space." + (let ((frame (or frame (selected-frame)))) + (cj/--ai-term-direction-for-aspect (frame-pixel-width frame) + (frame-pixel-height frame)))) (defun cj/--ai-term-default-size () - "Return the host-appropriate default size fraction for the agent window. - -`cj/ai-term-laptop-height' on a laptop, `cj/ai-term-desktop-width' -on a desktop -- pairing with the axis chosen by -`cj/--ai-term-default-direction'." - (if (env-laptop-p) - cj/ai-term-laptop-height - cj/ai-term-desktop-width)) + "Return the default size fraction paired with the chosen direction. + +`cj/ai-term-desktop-width' (a width fraction) when the default direction is +`right', `cj/ai-term-laptop-height' (a height fraction) when it is `below'." + (if (eq (cj/--ai-term-default-direction) 'right) + cj/ai-term-desktop-width + cj/ai-term-laptop-height)) (defvar cj/--ai-term-last-direction nil "Last user-chosen direction for the AI-term display. diff --git a/tests/test-ai-term--default-geometry.el b/tests/test-ai-term--default-geometry.el index 833f2ef4c..91013862d 100644 --- a/tests/test-ai-term--default-geometry.el +++ b/tests/test-ai-term--default-geometry.el @@ -1,15 +1,18 @@ ;;; test-ai-term--default-geometry.el --- Tests for host-aware display defaults -*- lexical-binding: t; -*- ;;; Commentary: -;; ai-term's default display geometry is host-aware: a laptop opens the -;; agent from the bottom (75% height), a desktop opens it from the right -;; (50% width). `cj/--ai-term-default-direction' and -;; `cj/--ai-term-default-size' encapsulate the `env-laptop-p' branch; -;; they feed the default fallbacks in `cj/--ai-term-capture-state' and +;; ai-term's default display geometry is chosen from the frame's pixel aspect +;; ratio: a landscape frame docks the agent from the right (a width fraction), a +;; square or portrait frame docks it from the bottom (a height fraction). +;; `cj/--ai-term-direction-for-aspect' is the pure decision; +;; `cj/--ai-term-default-direction' reads the frame and delegates to it; +;; `cj/--ai-term-default-size' pairs the size fraction with that direction. +;; They feed the default fallbacks in `cj/--ai-term-capture-state' and ;; `cj/--ai-term-display-saved'. ;; -;; `env-laptop-p' is stubbed per-test so the assertions are deterministic -;; regardless of the host the suite runs on. +;; The direction is tested on the pure helper (no frame mocking, which would +;; trip the native-comp trampoline trap on the frame-pixel-* subrs); the size +;; helper is tested by stubbing the direction defun. ;;; Code: @@ -19,37 +22,39 @@ (add-to-list 'load-path (expand-file-name "modules" user-emacs-directory)) (require 'ai-term) -(ert-deftest test-ai-term--default-direction-laptop () - "Normal: on a laptop the default direction is `below'." - (cl-letf (((symbol-function 'env-laptop-p) (lambda () t))) - (should (eq (cj/--ai-term-default-direction) 'below)))) +(ert-deftest test-ai-term--direction-for-aspect-landscape-is-right () + "Normal: a wider-than-tall frame docks from the right." + (should (eq (cj/--ai-term-direction-for-aspect 1920 1080) 'right))) -(ert-deftest test-ai-term--default-direction-desktop () - "Normal: on a desktop the default direction is `right'." - (cl-letf (((symbol-function 'env-laptop-p) (lambda () nil))) - (should (eq (cj/--ai-term-default-direction) 'right)))) +(ert-deftest test-ai-term--direction-for-aspect-portrait-is-below () + "Normal: a taller-than-wide frame docks from the bottom." + (should (eq (cj/--ai-term-direction-for-aspect 1080 1920) 'below))) -(ert-deftest test-ai-term--default-size-laptop () - "Normal: on a laptop the default size is `cj/ai-term-laptop-height'." +(ert-deftest test-ai-term--direction-for-aspect-square-is-below () + "Boundary: a square frame docks from the bottom (the conserving tie-break)." + (should (eq (cj/--ai-term-direction-for-aspect 1000 1000) 'below))) + +(ert-deftest test-ai-term--default-size-pairs-width-with-right () + "Normal: when the direction is `right' the size is the width fraction." (let ((cj/ai-term-laptop-height 0.75) (cj/ai-term-desktop-width 0.5)) - (cl-letf (((symbol-function 'env-laptop-p) (lambda () t))) - (should (= (cj/--ai-term-default-size) 0.75))))) + (cl-letf (((symbol-function 'cj/--ai-term-default-direction) (lambda (&rest _) 'right))) + (should (= (cj/--ai-term-default-size) 0.5))))) -(ert-deftest test-ai-term--default-size-desktop () - "Normal: on a desktop the default size is `cj/ai-term-desktop-width'." +(ert-deftest test-ai-term--default-size-pairs-height-with-below () + "Normal: when the direction is `below' the size is the height fraction." (let ((cj/ai-term-laptop-height 0.75) (cj/ai-term-desktop-width 0.5)) - (cl-letf (((symbol-function 'env-laptop-p) (lambda () nil))) - (should (= (cj/--ai-term-default-size) 0.5))))) + (cl-letf (((symbol-function 'cj/--ai-term-default-direction) (lambda (&rest _) 'below))) + (should (= (cj/--ai-term-default-size) 0.75))))) (ert-deftest test-ai-term--default-size-respects-custom-values () "Boundary: the helper returns the customized values, not the literals." (let ((cj/ai-term-laptop-height 0.6) (cj/ai-term-desktop-width 0.33)) - (cl-letf (((symbol-function 'env-laptop-p) (lambda () t))) + (cl-letf (((symbol-function 'cj/--ai-term-default-direction) (lambda (&rest _) 'below))) (should (= (cj/--ai-term-default-size) 0.6))) - (cl-letf (((symbol-function 'env-laptop-p) (lambda () nil))) + (cl-letf (((symbol-function 'cj/--ai-term-default-direction) (lambda (&rest _) 'right))) (should (= (cj/--ai-term-default-size) 0.33))))) (provide 'test-ai-term--default-geometry) |
