branch: externals/doc-view-follow commit 17d031e8d6b89963b044f89ee5e7aacd048ce4ed Author: Paul Nelson <ultr...@gmail.com> Commit: Paul Nelson <ultr...@gmail.com>
Improve sync function to handle multiple windows for document views * doc-dual-view.el (doc-dual-view--sync-pages): Completely rewrite to support more than two windows. Calculate relative page positions for each window based on the selected window's position. Use individual timers for each window's redisplay operation. (doc-dual-view--schedule-redisplay): New helper function to schedule redisplay operations for document windows. --- doc-dual-view.el | 106 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 67 insertions(+), 39 deletions(-) diff --git a/doc-dual-view.el b/doc-dual-view.el index 8329f18607..3c1314bffa 100644 --- a/doc-dual-view.el +++ b/doc-dual-view.el @@ -78,51 +78,79 @@ redisplay-func)." (< (cadr edges-a) (cadr edges-b)))))))) (defun doc-dual-view--sync-pages (&rest _args) - "Sync pages between two windows showing the same document." + "Sync pages between windows showing the same document." (let* ((mode-funcs (assoc major-mode doc-dual-view-modes)) (goto-funcs (nth 1 mode-funcs)) (current-page-func (nth 2 mode-funcs)) (max-page-func (nth 3 mode-funcs)) (redisplay-func (nth 4 mode-funcs))) (when mode-funcs - (let ((windows (doc-dual-view--order-windows - (get-buffer-window-list nil nil nil)))) - (when (= (length windows) 2) - (let* ((first-window (car windows)) - (second-window (cadr windows)) - (current-page (funcall current-page-func)) - (max-page (funcall max-page-func)) - (target-page (if (eq (selected-window) first-window) - (min (1+ current-page) max-page) - (max (1- current-page) 1)))) - (with-selected-window (if (eq (selected-window) first-window) - second-window - first-window) - (let ((other-current-page (funcall current-page-func))) - (when (not (= other-current-page target-page)) - ;; Temporarily remove advice to prevent recursion - (dolist (func goto-funcs) - (advice-remove func #'doc-dual-view--sync-pages)) - (unwind-protect - (progn - (funcall (car goto-funcs) target-page) - ;; Use timer for redisplay - (when doc-dual-view--redisplay-timer - (cancel-timer doc-dual-view--redisplay-timer)) - (setq doc-dual-view--redisplay-timer - (run-with-idle-timer - 0.001 nil - (lambda (win func page) - (when (window-live-p win) - (with-selected-window win - (funcall func page)))) - (selected-window) - redisplay-func - target-page))) - ;; Re-add advice after execution - (dolist (func goto-funcs) - (advice-add - func :after #'doc-dual-view--sync-pages)))))))))))) + (let* ((windows (doc-dual-view--order-windows + (get-buffer-window-list nil nil nil))) + (current-window (selected-window)) + (window-index (cl-position current-window windows)) + (current-page (funcall current-page-func)) + (max-page (funcall max-page-func))) + + ;; Only proceed if we found our window in the list and have multiple windows + (when (and window-index (> (length windows) 1)) + ;; Temporarily remove advice to prevent recursion + (dolist (func goto-funcs) + (advice-remove func #'doc-dual-view--sync-pages)) + + (unwind-protect + (progn + ;; Create a list of target pages for all windows + (let ((target-pages + (cl-loop for i from 0 below (length windows) + collect (cond + ((< i window-index) + (max 1 (- current-page (- window-index i)))) + ((> i window-index) + (min max-page (+ current-page (- i window-index)))) + (t current-page))))) + + ;; Apply the target pages to each window + (cl-loop for win in windows + for target-page in target-pages + for i from 0 + when (and (not (eq win current-window)) + (window-live-p win)) + do (with-selected-window win + (let ((current (funcall current-page-func))) + (when (not (= current target-page)) + (funcall (car goto-funcs) target-page) + ;; Use a unique timer for each window + (let ((timer-sym (intern (format "doc-dual-view--redisplay-timer-%d" i)))) + (when (and (boundp timer-sym) + (timerp (symbol-value timer-sym))) + (cancel-timer (symbol-value timer-sym))) + (set timer-sym + (run-with-idle-timer + 0.001 nil + (lambda (w f p) + (when (window-live-p w) + (with-selected-window w + (funcall f p)))) + win redisplay-func target-page))))))))) + + ;; Re-add advice after execution + (dolist (func goto-funcs) + (advice-add func :after #'doc-dual-view--sync-pages)))))))) + +(defun doc-dual-view--schedule-redisplay (window redisplay-func page) + "Schedule a redisplay for WINDOW using REDISPLAY-FUNC to show PAGE." + (when doc-dual-view--redisplay-timer + (cancel-timer doc-dual-view--redisplay-timer)) + (setq doc-dual-view--redisplay-timer + (run-with-idle-timer + 0.001 nil + (lambda (win func pg) + (when (window-live-p win) + (with-selected-window win + (funcall func pg)))) + window redisplay-func page))) + ;;;###autoload (define-minor-mode doc-dual-view-mode