diff --git a/config.el b/config.el index 3e7e1e5..ee44f22 100644 --- a/config.el +++ b/config.el @@ -698,12 +698,12 @@ Skips past the TODO keyword and optional priority indicator [#A]." ;;; ============================================================ ;;; ACCESSIBILITY — GLOBAL TEXT SCALING (SPC z) ;;; ============================================================ -;; True screen magnifier: scales the global `default' face (all buffers, -;; help windows, doom menus, org-agenda, magit — everything). +;; Screen magnifier: scales the global `default' face — all buffers, +;; help windows, doom menus, org-agenda, magit, which-key included. ;; -;; UI chrome (modeline, header-line) is PINNED to base size. -;; Intermediate layers (which-key, minibuffer/vertico) scale at a -;; reduced ratio so they remain readable at high zoom levels. +;; Modeline + header-line + tabs are PINNED to base size (always visible). +;; which-key shows at full zoom in 90 % of frame height — more keys fit. +;; No face-remap hooks (avoid accumulation bugs with timers). ;; ;; Step: ×1.5 per step (multiplicative). From 14pt base: ;; +1 ≈ 21pt +2 ≈ 32pt +3 ≈ 47pt @@ -713,149 +713,68 @@ Skips past the TODO keyword and optional priority indicator [#A]." ;; SPC z - zoom out ;; SPC z 0 reset to default (saves level for restore) ;; SPC z z restore zoom before last reset +;; In which-key popup: C-h pages to next group of bindings -;; --------------- state variables --------------- +;; --------------- state --------------- (defvar my/zoom-base-height 140 - "Default face height before any zoom. Captured at Doom init (1/10 pt).") + "Default face height before any zoom, in 1/10 pt. Captured at Doom init.") (defvar my/zoom-steps 0 - "Current zoom step count. 0 = default.") + "Current zoom step count. 0 = default, positive = bigger.") (defvar my/zoom-saved-steps nil "Step count saved before last `my/zoom-reset', for `my/zoom-restore'.") -;; --------------- tuning knobs --------------- - -(defvar my/zoom-which-key-ratio 0.3 - "Which-key font height as fraction of current default height. -At 110pt default this gives ~33pt — readable but compact.") - -(defvar my/zoom-minibuffer-ratio 0.4 - "Minibuffer font height as fraction of current default height. -At 110pt default this gives ~44pt — readable for vertico candidates.") - -;; --------------- pinned UI faces (fixed at base) --------------- +;; --------------- pinned faces (always at base) --------------- (defvar my/zoom-pinned-faces '(mode-line mode-line-inactive mode-line-active header-line tab-bar tab-bar-tab tab-bar-tab-inactive) - "Faces pinned to `my/zoom-base-height' after every zoom operation. -Note: minibuffer-prompt is NOT here — it gets intermediate scaling.") + "Faces kept at `my/zoom-base-height' regardless of zoom. +Keeps the status bar and tab bar fully visible at any zoom level.") (defun my/zoom-pin-ui () - "Set pinned UI faces to base height so they don't scale with text." + "Set all pinned UI faces to base height." (dolist (face my/zoom-pinned-faces) (when (facep face) (set-face-attribute face nil :height my/zoom-base-height)))) -;; --------------- which-key intermediate scaling --------------- +;; --------------- which-key: max side-window height --------------- +;; which-key scales with global zoom (same as all other buffers). +;; Give it 90 % of frame height so more bindings are visible at once. +;; Press C-h while which-key is open to page through remaining bindings. -(defvar my/zoom--which-key-cookie nil - "Face remap cookie for which-key buffer, so we can remove old remap.") - -(defun my/zoom--apply-which-key (new-height) - "Set which-key buffer face to intermediate size derived from NEW-HEIGHT." - (let* ((intermediate (max my/zoom-base-height - (round (* new-height my/zoom-which-key-ratio)))) - ;; Express as a ratio relative to the global default (new-height) - ;; because face-remap works relative to the buffer's inherited face. - (ratio (/ (float intermediate) new-height))) - (when-let ((buf (get-buffer " *which-key*"))) - (with-current-buffer buf - (when my/zoom--which-key-cookie - (face-remap-remove-relative my/zoom--which-key-cookie)) - (setq-local my/zoom--which-key-cookie - (face-remap-add-relative 'default :height ratio)))))) - -;; Hook: apply face remap whenever which-key creates/refreshes its buffer. -(defun my/zoom--which-key-buffer-setup () - "Apply intermediate font scaling when which-key buffer is initialized." - (when (and (string-prefix-p " *which-key*" (buffer-name)) - (/= my/zoom-steps 0)) - (let* ((current-h (face-attribute 'default :height nil t)) - (intermediate (max my/zoom-base-height - (round (* current-h my/zoom-which-key-ratio)))) - (ratio (/ (float intermediate) current-h))) - (setq-local my/zoom--which-key-cookie - (face-remap-add-relative 'default :height ratio))))) - -;; which-key-init-buffer-hook runs when the *which-key* buffer is set up -(add-hook 'which-key-init-buffer-hook #'my/zoom--which-key-buffer-setup) - -;; --------------- minibuffer intermediate scaling --------------- - -(defun my/zoom-update-minibuffer () - "Set minibuffer and echo area buffers to intermediate font size." - (let* ((current-h (face-attribute 'default :height nil t)) - (intermediate (max my/zoom-base-height - (round (* current-h my/zoom-minibuffer-ratio)))) - (ratio (/ (float intermediate) current-h))) - (dolist (buf-name '(" *Minibuf-0*" " *Minibuf-1*" - " *Echo Area 0*" " *Echo Area 1*")) - (when-let ((buf (get-buffer buf-name))) - (with-current-buffer buf - (setq-local face-remapping-alist - `((default (:height ,ratio) default)))))))) - -;; Hook: apply on every minibuffer entry (covers vertico, M-x, find-file). -(defun my/zoom--minibuffer-setup () - "Apply intermediate scaling to current minibuffer session." - (when (/= my/zoom-steps 0) - (let* ((current-h (face-attribute 'default :height nil t)) - (intermediate (max my/zoom-base-height - (round (* current-h my/zoom-minibuffer-ratio)))) - (ratio (/ (float intermediate) current-h))) - (setq-local face-remapping-alist - `((default (:height ,ratio) default)))))) - -(add-hook 'minibuffer-setup-hook #'my/zoom--minibuffer-setup) - -;; --------------- corfu popup refresh --------------- - -(defun my/zoom--invalidate-corfu () - "Hide corfu popup so it re-creates with new font on next completion." - (when (and (fboundp 'corfu-quit) (fboundp 'corfu--popup-hide)) - (ignore-errors (corfu--popup-hide)))) +(after! which-key + (setq which-key-side-window-max-height 0.90 + which-key-max-display-columns nil)) ;; --------------- core zoom engine --------------- (defun my/zoom--apply (steps) - "Set global default face to base × 1.5^STEPS and update all UI layers." + "Scale global default face to base × 1.5^STEPS and re-pin UI faces." (let ((new-h (max 80 (round (* my/zoom-base-height (expt 1.5 steps)))))) - ;; 1. Global default face — affects all buffer content (set-face-attribute 'default nil :height new-h) - - ;; 2. Pin modeline/header-line at base size (my/zoom-pin-ui) - - ;; 3. Which-key — intermediate font - (my/zoom--apply-which-key new-h) - - ;; 4. Minibuffer/echo area — intermediate font - (my/zoom-update-minibuffer) - - ;; 5. Corfu — force re-create on next completion - (my/zoom--invalidate-corfu) - + (when (fboundp 'corfu--popup-hide) + (ignore-errors (corfu--popup-hide))) (message "Zoom %+d ×%.2f ≈%dpt" steps (expt 1.5 steps) (/ new-h 10)))) -;; --------------- init: capture base height --------------- - +;; Capture base height once Doom finishes font setup. (add-hook 'doom-after-init-hook (lambda () (let ((h (face-attribute 'default :height nil t))) (when (and (integerp h) (> h 0)) (setq my/zoom-base-height h))))) -;; Re-pin UI faces after any theme reload (Doom resets faces on theme change). +;; Re-pin UI faces after theme reloads (Doom resets faces on theme change). (add-hook 'doom-load-theme-hook #'my/zoom-pin-ui) ;; --------------- interactive commands --------------- (defun my/zoom-in () - "Zoom in one step (×1.5) — all buffers, help, menus, everything." + "Zoom in one step (×1.5) — all buffers, help, menus, which-key." (interactive) (cl-incf my/zoom-steps) (my/zoom--apply my/zoom-steps)) @@ -867,7 +786,7 @@ Note: minibuffer-prompt is NOT here — it gets intermediate scaling.") (my/zoom--apply my/zoom-steps)) (defun my/zoom-reset () - "Reset to default font size. Saves current level so SPC z z can restore." + "Reset to default font size. Saves current level for restore." (interactive) (if (= my/zoom-steps 0) (message "Zoom: already at default")