;;; 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
  ;; HACK `pdf-tools-install-noverify' tries to "reset" open pdf-view-mode
  ;;      buffers, but does so incorrectly, causing errors when pdf-tools is
  ;;      loaded after opening a pdf file. We've done its job ourselves in
  ;;      `+pdf--install-epdfinfo-a' instead.
  (defadvice! +pdf--inhibit-pdf-view-mode-resets-a (orig-fn &rest args)
    :around #'pdf-tools-install-noverify
    (letf! ((#'pdf-tools-pdf-buffer-p #'ignore))
      (apply orig-fn args)))

  (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)
      ("\\(?:^\\*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))))))

  ;; Add retina support for MacOS users
  (eval-when! IS-MAC
    (defun +pdf-view-create-page-a (page &optional window)
      "Create an image of PAGE for display on WINDOW."
      :override #'pdf-view-create-page
      (let* ((size (pdf-view-desired-image-size page window))
             (width (if (not (pdf-view-use-scaling-p))
                        (car size)
                      (* 2 (car size))))
             (data (pdf-cache-renderpage
                    page width width))
             (hotspots (pdf-view-apply-hotspot-functions
                        window page size)))
        (pdf-view-create-image data
                               :width width
                               :scale (if (pdf-view-use-scaling-p) 0.5 1)
                               :map hotspots
                               :pointer 'arrow)))

    (defvar +pdf--scaled-p nil)
    (defadvice! +pdf--scale-up-on-retina-display-a (orig-fn &rest args)
      "Scale up the PDF on retina displays."
      :around #'pdf-util-frame-scale-factor
      (cond ((not pdf-view-use-scaling) 1)
            ((and (memq (pdf-view-image-type) '(imagemagick image-io))
                  (fboundp 'frame-monitor-attributes))
             (funcall orig-fn))
            ;; Add special support for retina displays on MacOS
            ((and (eq (framep-on-display) 'ns)
                  (not +pdf--scaled-p)
                  EMACS27+)
             (setq-local +pdf--scaled-p t)
             2)
            (1)))

    (defadvice! +pdf--use-scaling-on-ns-a ()
      :before-until #'pdf-view-use-scaling-p
      (and (eq (framep-on-display) 'ns)
           EMACS27+))

    (defadvice! +pdf--supply-width-to-create-image-calls-a (orig-fn &rest args)
      :around '(pdf-annot-show-annotation
                pdf-isearch-hl-matches
                pdf-view-display-region)
      (letf! (defun create-image (file-or-data &optional type data-p &rest props)
               (apply create-image file-or-data type data-p
                      :width (car (pdf-view-image-size))
                      props))
        (apply orig-fn args))))

  ;; Silence "File *.pdf is large (X MiB), really open?" prompts for pdfs
  (defadvice! +pdf-suppress-large-file-prompts-a (orig-fn size op-type filename &optional offer-raw)
    :around #'abort-if-file-too-large
    (unless (string-match-p "\\.pdf\\'" filename)
      (funcall orig-fn size op-type filename offer-raw))))


(use-package! saveplace-pdf-view
  :after pdf-view)
