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

Reply via email to