feat: comprehensive screen magnifier — text-scale + which-key fix + minibuffer
This commit is contained in:
127
config.el
127
config.el
@@ -701,11 +701,11 @@ Skips past the TODO keyword and optional priority indicator [#A]."
|
|||||||
;; True screen magnifier: scales the global `default' face (all buffers,
|
;; True screen magnifier: scales the global `default' face (all buffers,
|
||||||
;; help windows, doom menus, org-agenda, magit — everything).
|
;; help windows, doom menus, org-agenda, magit — everything).
|
||||||
;;
|
;;
|
||||||
;; Modeline + minibuffer are PINNED to base size after every zoom so they
|
;; UI chrome (modeline, header-line) is PINNED to base size.
|
||||||
;; stay fully visible and usable regardless of zoom level.
|
;; Intermediate layers (which-key, minibuffer/vertico) scale at a
|
||||||
;; which-key shows in the minibuffer area → also stays readable.
|
;; reduced ratio so they remain readable at high zoom levels.
|
||||||
;;
|
;;
|
||||||
;; Step: ×1.5 per step (multiplicative, not additive). From 14pt base:
|
;; Step: ×1.5 per step (multiplicative). From 14pt base:
|
||||||
;; +1 ≈ 21pt +2 ≈ 32pt +3 ≈ 47pt
|
;; +1 ≈ 21pt +2 ≈ 32pt +3 ≈ 47pt
|
||||||
;; +4 ≈ 71pt +5 ≈ 106pt +6 ≈ 159pt
|
;; +4 ≈ 71pt +5 ≈ 106pt +6 ≈ 159pt
|
||||||
;;
|
;;
|
||||||
@@ -714,10 +714,10 @@ Skips past the TODO keyword and optional priority indicator [#A]."
|
|||||||
;; SPC z 0 reset to default (saves level for restore)
|
;; SPC z 0 reset to default (saves level for restore)
|
||||||
;; SPC z z restore zoom before last reset
|
;; SPC z z restore zoom before last reset
|
||||||
|
|
||||||
;; Base height: captured once at startup (reflects doom-font :size).
|
;; --------------- state variables ---------------
|
||||||
;; Fallback to 140 = 14pt if face-attribute returns non-integer.
|
|
||||||
(defvar my/zoom-base-height 140
|
(defvar my/zoom-base-height 140
|
||||||
"Default face height before any zoom. Captured at Doom init.")
|
"Default face height before any zoom. Captured at Doom init (1/10 pt).")
|
||||||
|
|
||||||
(defvar my/zoom-steps 0
|
(defvar my/zoom-steps 0
|
||||||
"Current zoom step count. 0 = default.")
|
"Current zoom step count. 0 = default.")
|
||||||
@@ -725,13 +725,23 @@ Skips past the TODO keyword and optional priority indicator [#A]."
|
|||||||
(defvar my/zoom-saved-steps nil
|
(defvar my/zoom-saved-steps nil
|
||||||
"Step count saved before last `my/zoom-reset', for `my/zoom-restore'.")
|
"Step count saved before last `my/zoom-reset', for `my/zoom-restore'.")
|
||||||
|
|
||||||
;; Faces that must stay at base height (do not scale with text).
|
;; --------------- tuning knobs ---------------
|
||||||
;; These form the fixed UI chrome: status bar, minibuffer, tab bar.
|
|
||||||
|
(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) ---------------
|
||||||
|
|
||||||
(defvar my/zoom-pinned-faces
|
(defvar my/zoom-pinned-faces
|
||||||
'(mode-line mode-line-inactive mode-line-active
|
'(mode-line mode-line-inactive mode-line-active
|
||||||
minibuffer-prompt header-line
|
header-line tab-bar tab-bar-tab tab-bar-tab-inactive)
|
||||||
tab-bar tab-bar-tab tab-bar-tab-inactive)
|
"Faces pinned to `my/zoom-base-height' after every zoom operation.
|
||||||
"Faces pinned to `my/zoom-base-height' after every zoom operation.")
|
Note: minibuffer-prompt is NOT here — it gets intermediate scaling.")
|
||||||
|
|
||||||
(defun my/zoom-pin-ui ()
|
(defun my/zoom-pin-ui ()
|
||||||
"Set pinned UI faces to base height so they don't scale with text."
|
"Set pinned UI faces to base height so they don't scale with text."
|
||||||
@@ -739,15 +749,100 @@ Skips past the TODO keyword and optional priority indicator [#A]."
|
|||||||
(when (facep face)
|
(when (facep face)
|
||||||
(set-face-attribute face nil :height my/zoom-base-height))))
|
(set-face-attribute face nil :height my/zoom-base-height))))
|
||||||
|
|
||||||
|
;; --------------- which-key intermediate scaling ---------------
|
||||||
|
|
||||||
|
(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))))
|
||||||
|
|
||||||
|
;; --------------- core zoom engine ---------------
|
||||||
|
|
||||||
(defun my/zoom--apply (steps)
|
(defun my/zoom--apply (steps)
|
||||||
"Set global default face to base × 1.5^STEPS and re-pin UI faces."
|
"Set global default face to base × 1.5^STEPS and update all UI layers."
|
||||||
(let ((new-h (max 80 (round (* my/zoom-base-height (expt 1.5 steps))))))
|
(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)
|
(set-face-attribute 'default nil :height new-h)
|
||||||
|
|
||||||
|
;; 2. Pin modeline/header-line at base size
|
||||||
(my/zoom-pin-ui)
|
(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)
|
||||||
|
|
||||||
(message "Zoom %+d ×%.2f ≈%dpt"
|
(message "Zoom %+d ×%.2f ≈%dpt"
|
||||||
steps (expt 1.5 steps) (/ new-h 10))))
|
steps (expt 1.5 steps) (/ new-h 10))))
|
||||||
|
|
||||||
;; Capture base height after Doom finishes font setup.
|
;; --------------- init: capture base height ---------------
|
||||||
|
|
||||||
(add-hook 'doom-after-init-hook
|
(add-hook 'doom-after-init-hook
|
||||||
(lambda ()
|
(lambda ()
|
||||||
(let ((h (face-attribute 'default :height nil t)))
|
(let ((h (face-attribute 'default :height nil t)))
|
||||||
@@ -757,6 +852,8 @@ Skips past the TODO keyword and optional priority indicator [#A]."
|
|||||||
;; Re-pin UI faces after any theme reload (Doom resets faces on theme change).
|
;; Re-pin UI faces after any theme reload (Doom resets faces on theme change).
|
||||||
(add-hook 'doom-load-theme-hook #'my/zoom-pin-ui)
|
(add-hook 'doom-load-theme-hook #'my/zoom-pin-ui)
|
||||||
|
|
||||||
|
;; --------------- interactive commands ---------------
|
||||||
|
|
||||||
(defun my/zoom-in ()
|
(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, everything."
|
||||||
(interactive)
|
(interactive)
|
||||||
@@ -788,6 +885,8 @@ Skips past the TODO keyword and optional priority indicator [#A]."
|
|||||||
(setq my/zoom-steps my/zoom-saved-steps
|
(setq my/zoom-steps my/zoom-saved-steps
|
||||||
my/zoom-saved-steps nil)))
|
my/zoom-saved-steps nil)))
|
||||||
|
|
||||||
|
;; --------------- keybindings ---------------
|
||||||
|
|
||||||
(map! :leader
|
(map! :leader
|
||||||
(:prefix ("z" . "zoom")
|
(:prefix ("z" . "zoom")
|
||||||
:desc "Zoom in (×1.5)" "+" #'my/zoom-in
|
:desc "Zoom in (×1.5)" "+" #'my/zoom-in
|
||||||
|
|||||||
Reference in New Issue
Block a user