feat: split-screen magnifier + readable preset + centered-cursor-mode

This commit is contained in:
2026-02-22 20:54:09 +01:00
parent 14f15b3472
commit 8f3e46c22d

135
config.el
View File

@@ -33,12 +33,21 @@
(setq which-key-idle-delay 0.8
which-key-idle-secondary-delay 0.05)
;; Centered cursor mode — disabled: conflicts with macOS Zoom focus follower
;; Centered cursor mode — safe with macOS Zoom set to "Follow mouse cursor"
;; (NOT "Follow keyboard focus" — that causes viewport jumping)
(use-package! centered-cursor-mode
:config
(setq ccm-vpos-init 0.5)
;; (global-centered-cursor-mode +1) ; uncomment to enable
)
(setq ccm-vpos-init 0.5 ; cursor uprostřed obrazovky
ccm-step-size 2 ; plynulejší scroll
ccm-recenter-at-end-of-file t)
;; Vypnout v terminálu a speciálních módech
(define-globalized-minor-mode my/global-ccm
centered-cursor-mode
(lambda ()
(unless (memq major-mode '(vterm-mode eshell-mode term-mode
treemacs-mode pdf-view-mode))
(centered-cursor-mode 1))))
(my/global-ccm +1))
;;; ============================================================
@@ -804,6 +813,118 @@ Keeps the status bar and tab bar fully visible at any zoom level.")
(setq my/zoom-steps my/zoom-saved-steps
my/zoom-saved-steps nil)))
(defun my/zoom-readable ()
"Přepne na čitelný zoom preset (32pt ≈ step +2)."
(interactive)
(setq my/zoom-steps 2)
(my/zoom--apply my/zoom-steps))
;;; ============================================================
;;; ACCESSIBILITY — SPLIT-SCREEN MAGNIFIER (SPC z m)
;;; ============================================================
;; Dual-view: hlavní okno (normální font) + magnified okno (zvětšený).
;; Indirect buffer sdílí obsah, ale má vlastní text-scale.
;; Cursor pozice se synchronizuje přes post-command-hook.
(defvar my/mag--buffer nil "Indirect buffer pro magnified view.")
(defvar my/mag--source nil "Source buffer pro magnifier.")
(defvar my/mag--active nil "Je magnifier aktivní?")
(defvar my/mag--zoom-level 4
"Zoom level pro magnified view (text-scale steps). 4 ≈ 2.3× zvětšení.")
(defun my/mag-toggle ()
"Toggle split-screen magnifier. Vytvoří/zruší zvětšené okno vpravo."
(interactive)
(if my/mag--active
(my/mag--disable)
(my/mag--enable)))
(defun my/mag--enable ()
"Zapni magnified split view pro aktuální buffer."
(let* ((src (current-buffer))
(mag-name (format "*mag:%s*" (buffer-name src)))
(mag (or (get-buffer mag-name)
(make-indirect-buffer src mag-name t))))
(setq my/mag--buffer mag
my/mag--source src
my/mag--active t)
(with-current-buffer mag
(text-scale-set my/mag--zoom-level)
(setq-local display-line-numbers nil))
(split-window-right (floor (* 0.6 (window-width))))
(save-selected-window
(other-window 1)
(switch-to-buffer mag)
(goto-char (with-current-buffer src (point)))
(recenter))
(add-hook 'post-command-hook #'my/mag--sync)
(add-hook 'kill-buffer-hook #'my/mag--on-kill nil t)
(message "Magnifier ON (zoom +%d)" my/mag--zoom-level)))
(defun my/mag--disable ()
"Vypni magnifier a zavři magnified okno."
(remove-hook 'post-command-hook #'my/mag--sync)
(when (and my/mag--buffer (buffer-live-p my/mag--buffer))
(when-let ((win (get-buffer-window my/mag--buffer)))
(delete-window win))
(kill-buffer my/mag--buffer))
(setq my/mag--buffer nil
my/mag--source nil
my/mag--active nil)
(message "Magnifier OFF"))
(defun my/mag--on-kill ()
"Cleanup když se zavře source buffer."
(when (and my/mag--active
(eq (current-buffer) my/mag--source))
(my/mag--disable)))
(defun my/mag--sync ()
"Synchronizuj pozici kurzoru v magnified view."
(when (and my/mag--active
my/mag--buffer
(buffer-live-p my/mag--buffer)
my/mag--source
(eq (current-buffer) my/mag--source))
(let ((pos (point)))
(when-let ((win (get-buffer-window my/mag--buffer)))
(with-selected-window win
(goto-char pos)
(recenter))))))
(defun my/mag--follow-buffer ()
"Přepni magnifier na nový buffer když uživatel změní aktivní buffer."
(when (and my/mag--active
(not (eq (current-buffer) my/mag--source))
(not (minibufferp))
(not (string-prefix-p " " (buffer-name)))
(not (string-prefix-p "*mag:" (buffer-name))))
(my/mag--disable)
(my/mag--enable)))
(add-hook 'window-selection-change-functions
(lambda (_frame) (when my/mag--active
(run-with-idle-timer 0.1 nil #'my/mag--follow-buffer))))
(defun my/mag-zoom-in ()
"Zvětši zoom magnified view."
(interactive)
(cl-incf my/mag--zoom-level)
(when (and my/mag--buffer (buffer-live-p my/mag--buffer))
(with-current-buffer my/mag--buffer
(text-scale-set my/mag--zoom-level))
(message "Mag zoom: +%d" my/mag--zoom-level)))
(defun my/mag-zoom-out ()
"Zmenši zoom magnified view."
(interactive)
(cl-decf my/mag--zoom-level)
(when (and my/mag--buffer (buffer-live-p my/mag--buffer))
(with-current-buffer my/mag--buffer
(text-scale-set my/mag--zoom-level))
(message "Mag zoom: +%d" my/mag--zoom-level)))
;; --------------- keybindings ---------------
(map! :leader
@@ -812,7 +933,11 @@ Keeps the status bar and tab bar fully visible at any zoom level.")
:desc "Zoom in (×1.5)" "=" #'my/zoom-in
:desc "Zoom out (÷1.5)" "-" #'my/zoom-out
:desc "Reset na výchozí" "0" #'my/zoom-reset
:desc "Restore předchozí" "z" #'my/zoom-restore))
:desc "Restore předchozí" "z" #'my/zoom-restore
:desc "Readable (32pt)" "r" #'my/zoom-readable
:desc "Toggle magnifier" "m" #'my/mag-toggle
:desc "Mag zoom in" "M" #'my/mag-zoom-in
:desc "Mag zoom out" "N" #'my/mag-zoom-out))
;;; ============================================================