diff options
| author | Vedang Manerikar <ved.manerikar@gmail.com> | 2025-12-31 13:48:11 +0530 |
|---|---|---|
| committer | Vedang Manerikar <ved.manerikar@gmail.com> | 2025-12-31 23:01:15 +0530 |
| commit | 2603233d2b3814c75c762783327f1fd633f82549 (patch) | |
| tree | 5f6594652fa12f107e8ed29f63c115eda1b2168e /lisp/pdf-view.el | |
| parent | d54ba6423d8cdc34b79ba20c899616ad21d4a5bc (diff) | |
feat: integrate pdf-view-roll-minor-mode with existing features
Update all pdf-tools features to work correctly when
pdf-view-roll-minor-mode is active:
- pdf-isearch: Search across all displayed pages simultaneously
- pdf-links: Link selection works with multiple visible pages
- pdf-annot: Annotations work on correct page, add pdf-annot-edit
command for avy-style annotation editing
- pdf-sync: SyncTeX jumps work with continuous scroll mode
- pdf-view: Display and navigation functions updated for multi-page
- pdf-util: Coordinate transformation updates for visible pages
- pdf-cache: Simplify prefetch (remove timer indirection)
- pdf-occur: Minor compatibility updates
The mode is experimental. Some features may not interact perfectly
with roll mode. Enable with M-x pdf-view-roll-minor-mode.
API changes:
- pdf-view-active-region now includes page information
- isearch results include page data for multi-page display
Co-authored-by: Daniel Nicolai <dalanicolai@gmail.com>
Co-authored-by: Rahguzar <aikrahguzar@zohomail.eu>
Co-authored-by: Ihor Radchenko <yantar92@gmail.com>
Co-authored-by: NightMachinery <feraidoonmehri@gmail.com>
Diffstat (limited to 'lisp/pdf-view.el')
| -rw-r--r-- | lisp/pdf-view.el | 241 |
1 files changed, 150 insertions, 91 deletions
diff --git a/lisp/pdf-view.el b/lisp/pdf-view.el index 620e526..d1ff32f 100644 --- a/lisp/pdf-view.el +++ b/lisp/pdf-view.el @@ -36,6 +36,18 @@ (declare-function cua-copy-region "cua-base") (declare-function pdf-tools-pdf-buffer-p "pdf-tools") + +(declare-function pdf-roll-scroll-forward "pdf-roll") +(declare-function pdf-roll-scroll-backward "pdf-roll") +(declare-function pdf-roll-next-page "pdf-roll") +(declare-function pdf-roll-redisplay "pdf-roll") +(declare-function pdf-roll-pre-redisplay "pdf-roll") +(declare-function pdf-roll-page-overlay "pdf-roll") +(declare-function pdf-roll-page-at-current-pos "pdf-roll") +(declare-function pdf-roll-display-image "pdf-roll") + +(defvar pdf-view-roll-minor-mode nil) + ;; * ================================================================== * ;; * Customizations @@ -252,7 +264,7 @@ Must be one of `glyph', `word', or `line'." ;; * ================================================================== * (defvar-local pdf-view-active-region nil - "The active region as a list of edges. + "The active region as a cons cell of page and list of edges. Edge values are relative coordinates.") @@ -551,7 +563,8 @@ PNG images in Emacs buffers." This may be different from variable `buffer-file-name' when operating on a local copy of a remote file." (or pdf-view--buffer-file-name - (buffer-file-name))) + (buffer-file-name) + (buffer-file-name (buffer-base-buffer)))) (defun pdf-view--write-contents-function () "Function for `write-contents-functions' to save the buffer." @@ -734,7 +747,10 @@ windows." (setf (pdf-view-current-page window) page) (run-hooks 'pdf-view-change-page-hook)) (when (window-live-p window) - (pdf-view-redisplay window)) + (image-set-window-vscroll 0) + (if pdf-view-roll-minor-mode + (pdf-roll-pre-redisplay window) + (pdf-view-redisplay window))) (when changing-p (pdf-view-deactivate-region) (force-mode-line-update) @@ -860,7 +876,7 @@ to previous page only on typing DEL (ARG is nil)." (image-set-window-hscroll hscroll))) (image-scroll-down arg))) -(defun pdf-view-next-line-or-next-page (&optional arg) +(defun pdf-view--next-line-or-next-page (&optional arg) "Scroll upward by ARG lines if possible, else go to the next page. When `pdf-view-continuous' is non-nil, scrolling a line upward @@ -878,7 +894,13 @@ at the bottom edge of the page moves to the next page." (image-set-window-hscroll hscroll))) (image-next-line arg))) -(defun pdf-view-previous-line-or-previous-page (&optional arg) +(defun pdf-view-next-line-or-next-page (&optional arg) + (interactive "p") + (if pdf-view-roll-minor-mode + (dotimes (_ (or arg 1)) (pdf-roll-scroll-forward)) + (pdf-view--next-line-or-next-page arg))) + +(defun pdf-view--previous-line-or-previous-page (&optional arg) "Scroll downward by ARG lines if possible, else go to the previous page. When `pdf-view-continuous' is non-nil, scrolling a line downward @@ -896,6 +918,12 @@ at the top edge of the page moves to the previous page." (image-set-window-hscroll hscroll))) (image-previous-line arg))) +(defun pdf-view-previous-line-or-previous-page (&optional arg) + (interactive "p") + (if pdf-view-roll-minor-mode + (dotimes (_ (or arg 1)) (pdf-roll-scroll-backward)) + (pdf-view--previous-line-or-previous-page arg))) + (defun pdf-view-goto-label (label) "Go to the page corresponding to LABEL. @@ -1119,17 +1147,23 @@ See also `pdf-view-use-imagemagick'." :map hotspots :pointer 'arrow))) -(defun pdf-view-image-size (&optional displayed-p window) - ;; TODO: add WINDOW to docstring. - "Return the size in pixel of the current image. +(defun pdf-view-image-size (&optional displayed-p window page) + "Return the size in pixel of the current image in WINDOW. If DISPLAYED-P is non-nil, return the size of the displayed -image. These values may be different, if slicing is used." - (if displayed-p - (with-selected-window (or window (selected-window)) - (image-display-size - (image-get-display-property) t)) - (image-size (pdf-view-current-image window) t))) +image. These values may be different, if slicing is used. + +If PAGE is non-nil return its size instead of current page." + (let ((display-prop (if pdf-view-roll-minor-mode + (progn (setq window (if (windowp window) window (selected-window))) + (setq page (or page (pdf-view-current-page window))) + (unless (memq page (image-mode-window-get 'displayed-pages window)) + (pdf-view-display-page page window)) + (overlay-get (pdf-roll-page-overlay page window) 'display)) + (image-get-display-property)))) + (if displayed-p + (image-display-size display-prop t) + (image-size display-prop t)))) (defun pdf-view-image-offset (&optional window) ;; TODO: add WINDOW to docstring. @@ -1149,47 +1183,49 @@ It is equal to \(LEFT . TOP\) of the current slice in pixel." "Display page PAGE in WINDOW." (setf (pdf-view-window-needs-redisplay window) nil) (pdf-view-display-image - (pdf-view-create-page page window) - window)) + (pdf-view-create-page page window) page window)) -(defun pdf-view-display-image (image &optional window inhibit-slice-p) +(defun pdf-view-display-image (image page &optional window inhibit-slice-p) ;; TODO: write documentation! - (let ((ol (pdf-view-current-overlay window))) - (when (window-live-p (overlay-get ol 'window)) - (let* ((size (image-size image t)) - (slice (if (not inhibit-slice-p) - (pdf-view-current-slice window))) - (displayed-width (floor - (if slice - (* (nth 2 slice) - (car (image-size image))) - (car (image-size image)))))) - (setf (pdf-view-current-image window) image) - (move-overlay ol (point-min) (point-max)) - ;; In case the window is wider than the image, center the image - ;; horizontally. - (overlay-put ol 'before-string - (when (> (window-width window) - displayed-width) - (propertize " " 'display - `(space :align-to - ,(/ (- (window-width window) - displayed-width) 2))))) - (overlay-put ol 'display - (if slice - (list (cons 'slice - (pdf-util-scale slice size 'round)) - image) - image)) - (let* ((win (overlay-get ol 'window)) - (hscroll (image-mode-window-get 'hscroll win)) - (vscroll (image-mode-window-get 'vscroll win))) - ;; Reset scroll settings, in case they were changed. - (if hscroll (set-window-hscroll win hscroll)) - (if vscroll (set-window-vscroll - win vscroll pdf-view-have-image-mode-pixel-vscroll))))))) - -(defun pdf-view-redisplay (&optional window) + (if pdf-view-roll-minor-mode + (pdf-roll-display-image + image page (or window (selected-window)) inhibit-slice-p) + (let ((ol (pdf-view-current-overlay window))) + (when (window-live-p (overlay-get ol 'window)) + (let* ((size (image-size image t)) + (slice (if (not inhibit-slice-p) + (pdf-view-current-slice window))) + (displayed-width (floor + (if slice + (* (nth 2 slice) + (car (image-size image))) + (car (image-size image)))))) + (setf (pdf-view-current-image window) image) + (move-overlay ol (point-min) (point-max)) + ;; In case the window is wider than the image, center the image + ;; horizontally. + (overlay-put ol 'before-string + (when (> (window-width window) + displayed-width) + (propertize " " 'display + `(space :align-to + ,(/ (- (window-width window) + displayed-width) 2))))) + (overlay-put ol 'display + (if slice + (list (cons 'slice + (pdf-util-scale slice size 'round)) + image) + image)) + (let* ((win (overlay-get ol 'window)) + (hscroll (image-mode-window-get 'hscroll win)) + (vscroll (image-mode-window-get 'vscroll win))) + ;; Reset scroll settings, in case they were changed. + (if hscroll (set-window-hscroll win hscroll)) + (if vscroll (set-window-vscroll + win vscroll pdf-view-have-image-mode-pixel-vscroll)))))))) + +(defun pdf-view--redisplay (&optional window) "Redisplay page in WINDOW. If WINDOW is t, redisplay pages in all windows." @@ -1210,12 +1246,18 @@ If WINDOW is t, redisplay pages in all windows." (setf (pdf-view-window-needs-redisplay window) t))))) (force-mode-line-update))) +(defun pdf-view-redisplay (&optional window) + (if pdf-view-roll-minor-mode + (pdf-roll-redisplay window) + (pdf-view--redisplay window))) + (defun pdf-view-redisplay-pages (&rest pages) "Redisplay PAGES in all windows." (pdf-util-assert-pdf-buffer) (dolist (window (get-buffer-window-list nil nil t)) - (when (memq (pdf-view-current-page window) - pages) + (when (cl-some (lambda (page) (memq page pages)) + (or (image-mode-window-get 'displayed-pages window) + (list (pdf-view-current-page window)))) (pdf-view-redisplay window)))) (defun pdf-view-maybe-redisplay-resized-windows () @@ -1261,7 +1303,7 @@ If WINDOW is t, redisplay pages in all windows." ;; `window' property is only effective if its value is a window). (cl-assert (eq t (car winprops))) (delete-overlay ol)) - (image-mode-window-put 'overlay ol winprops) + (image-mode-window-put 'overlay ol) ;; Clean up some overlays. (dolist (ov (overlays-in (point-min) (point-max))) (when (and (windowp (overlay-get ov 'window)) @@ -1406,7 +1448,7 @@ current theme's colors." (pdf-util-assert-pdf-buffer) (pdf-cache-clear-images) (when get-theme - (pdf-view-set-theme-background)) + (pdf-view-set-theme-background)) (pdf-view-redisplay t)) (define-minor-mode pdf-view-themed-minor-mode @@ -1487,7 +1529,7 @@ supersede hotspots in lower ones." (setq deactivate-mark nil)) (defun pdf-view-active-region (&optional deactivate-p) - "Return the active region, a list of edges. + "Return the active region, as a cons cell of page number and list of edges. Deactivate the region if DEACTIVATE-P is non-nil." (pdf-view-assert-active-region) @@ -1537,9 +1579,14 @@ Stores the region in `pdf-view-active-region'." (setq begin-inside-image-p nil) (posn-x-y pos))) (abs-begin (posn-x-y pos)) + (page (if pdf-view-roll-minor-mode + (/ (+ 3 (posn-point pos)) 4) + (pdf-view-current-page))) + (margin (frame-char-height)) (selection-style (or selection-style pdf-view-selection-style)) pdf-view-continuous region) + (setq pdf-view-active-region (list page)) (when (pdf-util-track-mouse-dragging (event 0.05) (let* ((pos (event-start event)) (end (posn-object-x-y pos)) @@ -1579,23 +1626,33 @@ Stores the region in `pdf-view-active-region'." (+ (car begin) (car dxy)))) (max 0 (min (cdr size) (+ (cdr begin) (cdr dxy))))))))) - (let ((iregion (if rectangle-p - (list (min (car begin) (car end)) - (min (cdr begin) (cdr end)) - (max (car begin) (car end)) - (max (cdr begin) (cdr end))) - (list (car begin) (cdr begin) - (car end) (cdr end))))) + (let* ((iregion (if rectangle-p + (list (min (car begin) (car end)) + (min (cdr begin) (cdr end)) + (max (car begin) (car end)) + (max (cdr begin) (cdr end))) + (list (car begin) (cdr begin) + (car end) (cdr end)))) + (y (cdr (posn-x-y pos))) + (dy (- y (cdr abs-begin)))) (setq region (pdf-util-scale-pixel-to-relative iregion)) (pdf-view-display-region - (cons region pdf-view-active-region) + (cons page (cons region (cdr pdf-view-active-region))) rectangle-p selection-style) - (pdf-util-scroll-to-edges iregion))))) - (setq pdf-view-active-region - (append pdf-view-active-region - (list region))) + (if pdf-view-roll-minor-mode + (cond + ((and (> dy 0) (< (- (window-text-height window t) y) margin)) + (pdf-roll-scroll-forward + (min margin + (or (nth 3 (pos-visible-in-window-p (posn-point pos) window t)) 0)))) + ((and (< dy 0) (< (- y (window-header-line-height window)) margin)) + (pdf-roll-scroll-backward + (min margin + (or (nth 2 (pos-visible-in-window-p (posn-point pos) window t)) 0))))) + (pdf-util-scroll-to-edges iregion)))))) + (cl-callf append (cdr pdf-view-active-region) (list region)) (pdf-view--push-mark)))) (defun pdf-view-mouse-extend-region (event) @@ -1622,18 +1679,19 @@ This is more useful for commands like (let ((colors (pdf-util-face-colors (if rectangle-p 'pdf-view-rectangle 'pdf-view-region) (bound-and-true-p pdf-view-dark-minor-mode))) - (page (pdf-view-current-page)) + (page (car region)) (width (car (pdf-view-image-size)))) (pdf-view-display-image (pdf-view-create-image (if rectangle-p (pdf-info-renderpage-highlight page width nil - `(,(car colors) ,(cdr colors) 0.35 ,@region)) + `(,(car colors) ,(cdr colors) 0.35 ,@(cdr region))) (pdf-info-renderpage-text-regions page width nil selection-style nil - `(,(car colors) ,(cdr colors) ,@region))) - :width width)))) + `(,(car colors) ,(cdr colors) ,@(cdr region)))) + :width width) + (when pdf-view-roll-minor-mode page)))) (defun pdf-view-kill-ring-save () "Copy the region to the `kill-ring'." @@ -1648,7 +1706,7 @@ This is more useful for commands like (interactive) (pdf-view-deactivate-region) (setq pdf-view-active-region - (list (list 0 0 1 1))) + (cons (pdf-view-current-page) (list (list 0 0 1 1)))) (pdf-view--push-mark) (pdf-view-display-region)) @@ -1658,10 +1716,10 @@ This is more useful for commands like (mapcar (lambda (edges) (pdf-info-gettext - (pdf-view-current-page) + (car pdf-view-active-region) edges pdf-view-selection-style)) - pdf-view-active-region)) + (cdr pdf-view-active-region))) (defun pdf-view-extract-region-image (regions &optional page size output-buffer no-display-p) @@ -1683,11 +1741,11 @@ the `convert' program is used." (interactive (list (if (pdf-view-active-region-p) (pdf-view-active-region t) - '((0 0 1 1))))) + '(,(pdf-view-current-page) (0 0 1 1))))) (unless page - (setq page (pdf-view-current-page))) + (setq page (car regions))) (unless size - (setq size (pdf-view-image-size))) + (setq size (pdf-view-image-size nil nil page))) (unless output-buffer (setq output-buffer (get-buffer-create "*PDF image*"))) (let* ((images (mapcar (lambda (edges) @@ -1699,7 +1757,7 @@ the `convert' program is used." :crop-to edges) nil file nil 'no-message) file)) - regions)) + (cdr regions))) result) (unwind-protect (progn @@ -1758,23 +1816,25 @@ the selection styles." The optional, boolean args exclude certain attributes." (or pdf-view--bookmark-to-restore - (let ((displayed-p (eq (current-buffer) - (window-buffer)))) + (let ((win (car (cl-find-if #'window-live-p image-mode-winprops-alist + :key #'car-safe)))) (cons (buffer-name) - (append (bookmark-make-record-default nil t 1) + (append (bookmark-make-record-default + nil t (if pdf-view-roll-minor-mode (point) 1)) `(,(unless no-page - (cons 'page (pdf-view-current-page))) + (cons 'page (pdf-view-current-page win))) ,(unless no-slice - (cons 'slice (and displayed-p - (pdf-view-current-slice)))) + (cons 'slice (and win (pdf-view-current-slice win)))) ,(unless no-size (cons 'size pdf-view-display-size)) ,(unless no-origin (cons 'origin - (and displayed-p - (let ((edges (pdf-util-image-displayed-edges nil t))) + (and win + (let* ((edges (pdf-util-image-displayed-edges + win (eq (window-buffer win) (current-buffer))))) (pdf-util-scale-pixel-to-relative - (cons (car edges) (cadr edges)) nil t))))) + (cons (car edges) (cadr edges)) nil + (eq (current-buffer) (window-buffer)) win))))) (handler . pdf-view-bookmark-jump-handler))))))) ;;;###autoload @@ -1813,7 +1873,6 @@ See also `pdf-view-bookmark-make-record'." (when-let ((origin (bookmark-prop-get pdf-view--bookmark-to-restore 'origin)) (size (pdf-view-image-size t win))) - (image-set-window-hscroll (round (/ (* (car origin) (car size)) (frame-char-width)))) |
