fix: magnifier buffer-switch + cursor visibility (architect-critic-coder pipeline)
This commit is contained in:
137
config.el
137
config.el
@@ -824,16 +824,15 @@ Keeps the status bar and tab bar fully visible at any zoom level.")
|
|||||||
;; RIGHT pane (60%): zvětšený pohled — indirect buffer, sleduje cursor
|
;; RIGHT pane (60%): zvětšený pohled — indirect buffer, sleduje cursor
|
||||||
;;
|
;;
|
||||||
;; Funkce:
|
;; Funkce:
|
||||||
;; - Sleduje cursor v aktivním okně (post-command-hook)
|
;; - Sleduje cursor v aktivním okně (post-command-hook + buffer-list-update-hook)
|
||||||
;; - Přepíná automaticky při změně bufferu/okna (buffer switch)
|
;; - Přepíná automaticky při změně bufferu/okna
|
||||||
;; - SPC z + / SPC z = zoom in (jen magnifier, ne globálně)
|
;; - SPC z + / SPC z = zoom in (jen magnifier, ne globálně)
|
||||||
;; - SPC z - zoom out (jen magnifier)
|
;; - SPC z - zoom out (jen magnifier)
|
||||||
;; - SPC z 0 reset zoom magnifieru na výchozí
|
;; - SPC z 0 reset zoom magnifieru na výchozí
|
||||||
;; - SPC z m toggle on/off
|
;; - SPC z m toggle on/off
|
||||||
;; - Všechny zoom příkazy jsou no-op pokud magnifier vypnut
|
;; - Kurzor v magnifier pane viditelný (hollow cursor v non-selected windows)
|
||||||
;; - Kurzor v magnifier pane skrytý (cursor-type nil)
|
;; - Magnifier pane je dedicated — Emacs do něj neotevírá jiné buffery
|
||||||
;; - Magnifier pane je read-only zobrazení (žádné edit v indirect buf)
|
;; - Správné cleanup při window close, buffer kill, workspace switch
|
||||||
;; - Správné cleanup při window-configuration-change
|
|
||||||
|
|
||||||
(defvar my/mag--active nil "Non-nil when split magnifier is enabled.")
|
(defvar my/mag--active nil "Non-nil when split magnifier is enabled.")
|
||||||
(defvar my/mag--window nil "The magnified (right) window.")
|
(defvar my/mag--window nil "The magnified (right) window.")
|
||||||
@@ -848,51 +847,64 @@ Keeps the status bar and tab bar fully visible at any zoom level.")
|
|||||||
(kill-buffer my/mag--buffer))
|
(kill-buffer my/mag--buffer))
|
||||||
(setq my/mag--buffer nil))
|
(setq my/mag--buffer nil))
|
||||||
|
|
||||||
|
(defun my/mag--setup-mag-window ()
|
||||||
|
"Configure magnifier window display settings.
|
||||||
|
Call after `set-window-buffer' on `my/mag--window'."
|
||||||
|
(when (and my/mag--window (window-live-p my/mag--window))
|
||||||
|
(set-window-dedicated-p my/mag--window t)
|
||||||
|
(set-window-parameter my/mag--window 'no-other-window t)
|
||||||
|
(with-selected-window my/mag--window
|
||||||
|
(text-scale-set my/mag--zoom-level)
|
||||||
|
(setq-local cursor-type 'box)
|
||||||
|
(setq-local cursor-in-non-selected-windows 'hollow)
|
||||||
|
(setq-local scroll-margin 0)
|
||||||
|
(when (bound-and-true-p display-line-numbers-mode)
|
||||||
|
(display-line-numbers-mode -1))
|
||||||
|
(when (bound-and-true-p hl-line-mode)
|
||||||
|
(hl-line-mode -1)))))
|
||||||
|
|
||||||
|
(defun my/mag--valid-source-p (buf)
|
||||||
|
"Return non-nil if BUF is a valid magnifier source buffer."
|
||||||
|
(and (buffer-live-p buf)
|
||||||
|
(not (minibufferp buf))
|
||||||
|
(not (string-prefix-p " " (buffer-name buf)))
|
||||||
|
(not (string-prefix-p "*mag:" (buffer-name buf)))))
|
||||||
|
|
||||||
(defun my/mag--switch-source ()
|
(defun my/mag--switch-source ()
|
||||||
"Switch magnifier to track the current buffer."
|
"Switch magnifier to track the current buffer."
|
||||||
(cl-block my/mag--switch-source
|
(let ((new-source (window-buffer (selected-window))))
|
||||||
(let* ((new-source (current-buffer))
|
(when (my/mag--valid-source-p new-source)
|
||||||
(mag-name (format "*mag:%s*" (buffer-name new-source))))
|
|
||||||
;; Don't switch to transient/minibuffer buffers
|
|
||||||
(when (or (minibufferp new-source)
|
|
||||||
(string-prefix-p " " (buffer-name new-source)))
|
|
||||||
(cl-return-from my/mag--switch-source))
|
|
||||||
(my/mag--kill-indirect)
|
(my/mag--kill-indirect)
|
||||||
(setq my/mag--source new-source)
|
(setq my/mag--source new-source)
|
||||||
(setq my/mag--buffer (make-indirect-buffer new-source mag-name t))
|
(let ((mag-name (format "*mag:%s*" (buffer-name new-source))))
|
||||||
|
;; Clean up stale buffer with same name
|
||||||
|
(when-let ((old (get-buffer mag-name)))
|
||||||
|
(kill-buffer old))
|
||||||
|
(setq my/mag--buffer (make-indirect-buffer new-source mag-name t)))
|
||||||
(when (and my/mag--window (window-live-p my/mag--window))
|
(when (and my/mag--window (window-live-p my/mag--window))
|
||||||
|
(set-window-dedicated-p my/mag--window nil) ; temporarily un-dedicate
|
||||||
(set-window-buffer my/mag--window my/mag--buffer)
|
(set-window-buffer my/mag--window my/mag--buffer)
|
||||||
(with-selected-window my/mag--window
|
(my/mag--setup-mag-window)))))
|
||||||
(text-scale-set my/mag--zoom-level)
|
|
||||||
(setq-local cursor-type 'box)
|
|
||||||
(setq-local scroll-margin 0)
|
|
||||||
(when (bound-and-true-p display-line-numbers-mode)
|
|
||||||
(display-line-numbers-mode -1))
|
|
||||||
(when (bound-and-true-p hl-line-mode)
|
|
||||||
(hl-line-mode -1)))))))
|
|
||||||
|
|
||||||
(defun my/mag--sync ()
|
(defun my/mag--sync ()
|
||||||
"Sync magnified pane to current cursor position."
|
"Sync magnified pane to current cursor position."
|
||||||
(when my/mag--active
|
(when (and my/mag--active
|
||||||
;; Skip when minibuffer is active (M-x, vertico, which-key, etc.)
|
my/mag--window (window-live-p my/mag--window)
|
||||||
(when (or (active-minibuffer-window)
|
(not (active-minibuffer-window))
|
||||||
(window-minibuffer-p))
|
(not (window-minibuffer-p))
|
||||||
(cl-return-from my/mag--sync))
|
(not (eq (selected-window) my/mag--window))
|
||||||
;; Ignore if we're in the magnifier pane itself
|
(not (window-parameter (selected-window) 'window-side)))
|
||||||
(when (eq (selected-window) my/mag--window)
|
(let ((cur-buf (window-buffer (selected-window))))
|
||||||
(cl-return-from my/mag--sync))
|
;; Switch source if buffer changed (only for valid buffers)
|
||||||
;; Check magnifier window is still alive
|
(when (and (not (eq cur-buf my/mag--source))
|
||||||
(unless (and my/mag--window (window-live-p my/mag--window))
|
(my/mag--valid-source-p cur-buf))
|
||||||
(cl-return-from my/mag--sync))
|
(my/mag--switch-source))
|
||||||
;; Switch source if buffer changed
|
;; Sync point + recenter
|
||||||
(unless (eq (current-buffer) my/mag--source)
|
(when (and my/mag--buffer (buffer-live-p my/mag--buffer))
|
||||||
(my/mag--switch-source))
|
(let ((pt (window-point (selected-window))))
|
||||||
;; Sync point + recenter
|
(with-selected-window my/mag--window
|
||||||
(when (and my/mag--buffer (buffer-live-p my/mag--buffer))
|
(goto-char pt)
|
||||||
(let ((pt (point)))
|
(recenter)))))))
|
||||||
(with-selected-window my/mag--window
|
|
||||||
(goto-char pt)
|
|
||||||
(recenter))))))
|
|
||||||
|
|
||||||
(defun my/mag--on-window-change ()
|
(defun my/mag--on-window-change ()
|
||||||
"Clean up if magnifier window was closed by user."
|
"Clean up if magnifier window was closed by user."
|
||||||
@@ -901,6 +913,23 @@ Keeps the status bar and tab bar fully visible at any zoom level.")
|
|||||||
(not (and my/mag--window (window-live-p my/mag--window))))
|
(not (and my/mag--window (window-live-p my/mag--window))))
|
||||||
(my/mag--disable)))
|
(my/mag--disable)))
|
||||||
|
|
||||||
|
(defun my/mag--on-source-killed ()
|
||||||
|
"Handle source buffer being killed."
|
||||||
|
(when (and my/mag--active
|
||||||
|
(eq (current-buffer) my/mag--source))
|
||||||
|
;; Try to switch to another visible buffer, or disable
|
||||||
|
(let ((alt (cl-find-if
|
||||||
|
(lambda (b)
|
||||||
|
(and (not (eq b (current-buffer)))
|
||||||
|
(my/mag--valid-source-p b)))
|
||||||
|
(buffer-list))))
|
||||||
|
(if alt
|
||||||
|
(progn
|
||||||
|
(set-window-buffer (selected-window) alt)
|
||||||
|
(setq my/mag--source nil) ; force switch
|
||||||
|
(my/mag--switch-source))
|
||||||
|
(my/mag--disable)))))
|
||||||
|
|
||||||
(defun my/mag--enable ()
|
(defun my/mag--enable ()
|
||||||
"Enable split-screen magnifier."
|
"Enable split-screen magnifier."
|
||||||
(delete-other-windows)
|
(delete-other-windows)
|
||||||
@@ -916,24 +945,32 @@ Keeps the status bar and tab bar fully visible at any zoom level.")
|
|||||||
(floor (* 0.4 (window-total-width)))
|
(floor (* 0.4 (window-total-width)))
|
||||||
'right))
|
'right))
|
||||||
(set-window-buffer my/mag--window my/mag--buffer)
|
(set-window-buffer my/mag--window my/mag--buffer)
|
||||||
(with-selected-window my/mag--window
|
(my/mag--setup-mag-window)
|
||||||
(text-scale-set my/mag--zoom-level)
|
|
||||||
(setq-local cursor-type 'box)
|
|
||||||
(setq-local scroll-margin 0)
|
|
||||||
(when (bound-and-true-p display-line-numbers-mode)
|
|
||||||
(display-line-numbers-mode -1))
|
|
||||||
(when (bound-and-true-p hl-line-mode)
|
|
||||||
(hl-line-mode -1)))
|
|
||||||
(setq my/mag--active t)
|
(setq my/mag--active t)
|
||||||
(add-hook 'post-command-hook #'my/mag--sync)
|
(add-hook 'post-command-hook #'my/mag--sync)
|
||||||
|
(add-hook 'buffer-list-update-hook #'my/mag--sync)
|
||||||
(add-hook 'window-configuration-change-hook #'my/mag--on-window-change)
|
(add-hook 'window-configuration-change-hook #'my/mag--on-window-change)
|
||||||
|
(add-hook 'kill-buffer-hook #'my/mag--on-source-killed)
|
||||||
|
(when (boundp 'persp-activated-functions)
|
||||||
|
(add-hook 'persp-activated-functions #'my/mag--on-persp-change))
|
||||||
(message "Split magnifier ON (zoom %+d)" my/mag--zoom-level))
|
(message "Split magnifier ON (zoom %+d)" my/mag--zoom-level))
|
||||||
|
|
||||||
|
(defun my/mag--on-persp-change (&rest _)
|
||||||
|
"Disable magnifier if window is dead after workspace switch."
|
||||||
|
(when (and my/mag--active
|
||||||
|
(not (window-live-p my/mag--window)))
|
||||||
|
(my/mag--disable)))
|
||||||
|
|
||||||
(defun my/mag--disable ()
|
(defun my/mag--disable ()
|
||||||
"Disable split-screen magnifier."
|
"Disable split-screen magnifier."
|
||||||
(remove-hook 'post-command-hook #'my/mag--sync)
|
(remove-hook 'post-command-hook #'my/mag--sync)
|
||||||
|
(remove-hook 'buffer-list-update-hook #'my/mag--sync)
|
||||||
(remove-hook 'window-configuration-change-hook #'my/mag--on-window-change)
|
(remove-hook 'window-configuration-change-hook #'my/mag--on-window-change)
|
||||||
|
(remove-hook 'kill-buffer-hook #'my/mag--on-source-killed)
|
||||||
|
(when (boundp 'persp-activated-functions)
|
||||||
|
(remove-hook 'persp-activated-functions #'my/mag--on-persp-change))
|
||||||
(when (and my/mag--window (window-live-p my/mag--window))
|
(when (and my/mag--window (window-live-p my/mag--window))
|
||||||
|
(set-window-dedicated-p my/mag--window nil)
|
||||||
(delete-window my/mag--window))
|
(delete-window my/mag--window))
|
||||||
;; Kill all *mag:* buffers
|
;; Kill all *mag:* buffers
|
||||||
(dolist (buf (buffer-list))
|
(dolist (buf (buffer-list))
|
||||||
|
|||||||
Reference in New Issue
Block a user