blob: 6a446938ce7b7f3baf1c1d7d8abd0d4f283f5ed5 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
;;; jao-pdf.el --- utilities for pdf files -*- lexical-binding: t; -*-
;; Copyright (C) 2022 jao
;; Author: jao <mail@jao.io>
;; Keywords: docs
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
;; Some niceties for PDFs:
;;
;; - Using mutools, we can extract the outline of PDFs, and tell back the
;; section title of a given page.
;; - Interoperability with zathura.
(require 'jao-doc-session)
;;; PDF info
(declare-function 'pdf-info-outline "pdf-info")
(defvar-local jao-pdf--outline nil)
(defun jao-pdf-is-pdf-file (file)
"Simply checks the FILE extension."
(string-match-p ".*\\.pdf$" file))
(defun jao-pdf-title-to-file-name (title)
"Convert a title, possibly with embedded spaces, to a PDF filename."
(concat (mapconcat 'downcase (split-string title nil t) "-") ".pdf"))
(defvar jao-pdf--outline-rx
".+\\(\t+\\)\"\\(.+\\)\"\t#\\(?:page=\\)?\\([0-9]+\\)")
(defun jao-pdf-outline (file-name)
"Return an alist describing the given FILE-NAME (or current if nil).
The result is cached as a local buffer variable."
(if (derived-mode-p 'pdf-view-mode)
(pdf-info-outline)
(let* ((outline nil)
(fn (or file-name (buffer-file-name)))
(fn (shell-quote-argument (expand-file-name fn))))
(with-temp-buffer
(insert (shell-command-to-string (format "mutool show %s outline" fn)))
(goto-char (point-min))
(while (re-search-forward jao-pdf--outline-rx nil t)
(push `((level . ,(length (match-string 1)))
(title . ,(match-string 2))
(page . ,(string-to-number (match-string 3))))
outline)))
(nreverse outline))))
(defun jao-pdf-title (&optional fname)
(if (or fname (not (derived-mode-p 'doc-view-mode 'pdf-view-mode)))
(let ((base (file-name-base (or fname (buffer-file-name)))))
(capitalize (replace-regexp-in-string "-" " " base)))
(or (jao-pdf-section-title)
(when buffer-file-name (jao-pdf-title buffer-file-name)))))
(defun jao-pdf-section-title (&optional page file-name)
(when (not jao-pdf--outline)
(setq-local jao-pdf--outline (jao-pdf-outline file-name)))
(let ((page (or page
(and (derived-mode-p 'doc-view-mode) (doc-view-current-page))
(and (derived-mode-p 'pdf-view) (pdf-view-current-page))))
(outline jao-pdf--outline)
(cur-page 0)
(cur-title (jao-pdf-title (or file-name buffer-file-name "title"))))
(while (and (car outline) (< cur-page page))
(setq cur-page (cdr (assoc 'page (car outline))))
(when (<= cur-page page)
(setq cur-title (cdr (assoc 'title (car outline)))))
(setq outline (cdr outline)))
(replace-regexp-in-string "[[:blank:]]+" " " cur-title)))
;;; zathura interop
(defun jao-pdf-zathura-open-cmd (file page &optional suffix)
(let ((page (if page (format "-P %s" page) "")))
(format "zathura %s %s %s" file page (or suffix ""))))
(defun jao-pdf-zathura-file-info (title)
(when (string-match "\\(.+\\) \\[\\(.+\\) (\\([0-9]+\\)/\\([0-9]+\\))\\]"
title)
(list (expand-file-name (match-string 1 title))
(string-to-number (match-string 3 title))
(string-to-number (match-string 4 title))
(match-string 2 title))))
(defun jao-pdf-goto-zathura-org (title &optional no-ask)
(when-let* ((info (jao-pdf-zathura-file-info title))
(pdf-file (car info))
(file (jao-org-pdf-to-org-file pdf-file))
(page (cadr info))
(pageno (or (car (last info)) page)))
(ignore-errors (jao-afio-goto-docs))
(let ((exists (file-exists-p file)))
(find-file file)
(unless exists (jao-org-insert-doc-skeleton))
(let* ((fn (file-name-nondirectory pdf-file))
(desc (jao-pdf-section-title page pdf-file))
(lnk (format "[[doc:%s::%d][%s (p. %s)]]" fn page desc pageno)))
(jao-doc-session-mark)
(if (or (not exists) (and (not no-ask) (y-or-n-p "Insert link?")))
(insert lnk "\n")
(kill-new lnk)
(message "Link to %s (%s) killed" file page))))))
(provide 'jao-pdf)
;;; jao-pdf.el ends here
|