fix: remove accumulating which-key face-remap (wholenump -2 bug); which-key 90% height

This commit is contained in:
2026-02-22 15:45:31 +01:00
parent 5bfc11a766
commit 14f15b3472

135
config.el
View File

@@ -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")