summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Nelson <ultrono@gmail.com>2025-04-01 21:51:34 +0200
committerPaul Nelson <ultrono@gmail.com>2025-04-01 21:51:34 +0200
commit17d031e8d6b89963b044f89ee5e7aacd048ce4ed (patch)
tree36de0cb3432405f0092b58fd686f57fbbfb4bc5c
parenta6367597c59c44f1d41697cd649795524162235a (diff)
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.
-rw-r--r--doc-dual-view.el106
1 files changed, 67 insertions, 39 deletions
diff --git a/doc-dual-view.el b/doc-dual-view.el
index 8329f18..3c1314b 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