doomemacs/modules/tools/pdf/config.el
Henrik Lissner 6c0881c684
nit: revise TODO/FIXME/HACK/REVIEW/etc in comments
Some were outdated, some were incorrectly labeled, others were already
completed, some were missing... Gotta fix them all.

Also, in :ui hl-todo, there are comments that describe how Doom uses
each of these annotations; those have been updated.
2026-03-02 19:45:09 -05:00

127 lines
5.7 KiB
EmacsLisp

;;; tools/pdf/config.el -*- lexical-binding: t; -*-
(use-package! pdf-tools
:mode ("\\.pdf\\'" . pdf-view-mode)
:magic ("%PDF" . pdf-view-mode)
:init
(after! pdf-annot
(defun +pdf-cleanup-windows-h ()
"Kill left-over annotation buffers when the document is killed."
(when (buffer-live-p pdf-annot-list-document-buffer)
(pdf-info-close pdf-annot-list-document-buffer))
(when (buffer-live-p pdf-annot-list-buffer)
(kill-buffer pdf-annot-list-buffer))
(let ((contents-buffer (get-buffer "*Contents*")))
(when (and contents-buffer (buffer-live-p contents-buffer))
(kill-buffer contents-buffer))))
(add-hook! 'pdf-view-mode-hook
(add-hook 'kill-buffer-hook #'+pdf-cleanup-windows-h nil t)))
:config
(defadvice! +pdf--install-epdfinfo-a (fn &rest args)
"Install epdfinfo after the first PDF file, if needed."
:around #'pdf-view-mode
(if (and (require 'pdf-info nil t)
(or (pdf-info-running-p)
(ignore-errors (pdf-info-check-epdfinfo) t)))
(apply fn args)
;; If we remain in pdf-view-mode, it'll spit out cryptic errors. This
;; graceful failure is better UX.
(fundamental-mode)
(message "Viewing PDFs in Emacs requires epdfinfo. Use `M-x pdf-tools-install' to build it")))
;; Despite its namesake, this does not call `pdf-tools-install', it only sets
;; up hooks, auto-mode-alist/magic-mode-alist entries, global modes, and
;; refreshes pdf-view-mode buffers, if any.
;;
;; I avoid calling `pdf-tools-install' directly because `pdf-tools' is easy to
;; prematurely load in the background (e.g. when exporting an org file or by
;; packages like org-pdftools). And I don't want pdf-tools to suddenly block
;; Emacs and spew out compiler output for a few minutes in those cases. It's
;; abysmal UX. The `pdf-view-mode' advice above works around this with a less
;; cryptic failure message, at least.
(pdf-tools-install-noverify)
;; For consistency with other special modes
(map! :map pdf-view-mode-map :gn "q" #'kill-current-buffer)
(setq-default pdf-view-display-size 'fit-page)
;; Enable hiDPI support, but at the cost of memory! See politza/pdf-tools#51
(setq pdf-view-use-scaling t
pdf-view-use-imagemagick nil)
;; Handle PDF-tools related popups better
(set-popup-rules!
'(("^\\*Outline*" :side right :size 40 :select nil)
("^\\*Edit Annotation " :quit nil)
("\\(?:^\\*Contents\\|'s annots\\*$\\)" :ignore t)))
;; The mode-line does serve any useful purpose is annotation windows
(add-hook 'pdf-annot-list-mode-hook #'hide-mode-line-mode)
;; HACK: Fix #1107: flickering pdfs when evil-mode is enabled
(setq-hook! 'pdf-view-mode-hook evil-normal-state-cursor (list nil))
;; HACK: Refresh FG/BG for pdfs when `pdf-view-midnight-colors' is changed by
;; a theme or with `setq!'.
;; TODO: PR this upstream?
(defun +pdf-reload-midnight-minor-mode-h ()
(when pdf-view-midnight-minor-mode
(pdf-info-setoptions
:render/foreground (car pdf-view-midnight-colors)
:render/background (cdr pdf-view-midnight-colors)
:render/usecolors t)
(pdf-cache-clear-images)
(pdf-view-redisplay t)))
(put 'pdf-view-midnight-colors 'custom-set
(lambda (sym value)
(set-default sym value)
(dolist (buffer (doom-buffers-in-mode 'pdf-view-mode))
(with-current-buffer buffer
(if (get-buffer-window buffer)
(+pdf-reload-midnight-minor-mode-h)
;; Defer refresh for buffers that aren't visible, to avoid
;; blocking Emacs for too long while changing themes.
(add-hook 'doom-switch-buffer-hook #'+pdf-reload-midnight-minor-mode-h
nil 'local))))))
;; Silence "File *.pdf is large (X MiB), really open?" prompts for pdfs
(defadvice! +pdf-suppress-large-file-prompts-a (fn size op-type filename &optional offer-raw)
:around #'abort-if-file-too-large
(unless (string-match-p "\\.pdf\\'" filename)
(funcall fn size op-type filename offer-raw))))
(use-package! saveplace-pdf-view
:after pdf-view)
(use-package! org-pdftools
:when (modulep! :lang org)
:commands org-pdftools-export
:init
(after! org
;; HACK: Fixes an issue where org-pdftools link handlers will throw a
;; 'pdf-info-epdfinfo-program is not executable' error whenever any link
;; is stored or exported (whether or not they're a pdf link). This error
;; gimps org until `pdf-tools-install' is run, but this is poor UX, so we
;; suppress it.
(defun +pdf--org-link-handler (fn &rest _args)
"Produces a link handler for org-pdftools that suppresses missing-epdfinfo
errors whenever storing or exporting links."
(lambda (&rest args)
(and (ignore-errors (require 'org-pdftools nil t))
(file-executable-p pdf-info-epdfinfo-program)
(apply fn args))))
(org-link-set-parameters (or (bound-and-true-p org-pdftools-link-prefix) "pdf")
:follow (+pdf--org-link-handler #'org-pdftools-open)
:complete (+pdf--org-link-handler #'org-pdftools-complete-link)
:store (+pdf--org-link-handler #'org-pdftools-store-link)
:export (+pdf--org-link-handler #'org-pdftools-export))
(add-hook! 'org-open-link-functions
(defun +pdf-open-legacy-links-fn (link)
"Open pdftools:* and pdfviews:* links as if they were pdf:* links."
(let ((regexp "^pdf\\(?:tools\\|view\\):"))
(when (string-match-p regexp link)
(org-pdftools-open (replace-regexp-in-string regexp "" link))
t))))))