[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Org mode links: Open a PDF file at a given page and highlight a give
From: |
Maxim Nikulin |
Subject: |
Re: Org mode links: Open a PDF file at a given page and highlight a given string |
Date: |
Fri, 5 Mar 2021 20:02:37 +0700 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.7.1 |
On 03/03/2021 23:11, Juan Manuel Macías wrote:
Maxim Nikulin writes:
Please, do not forget to pass stings coming from user input through
shell-quote-argument.
So, maybe it would look better like this (`start-process' instead of
`start-process-shell-command')?:
My intention was just to warn you against of opening a door
to shell injections.
Personally, as a workaround I would add an org-file-apps entry with
a single argument combining page and search string and would write
a tiny script that splits such argument and invokes the viewer.
I consider it as a better option in the sense of forward compatibility
since it allows to avoid custom link types. I expect that the bug
will be fixed soon.
I still suppose that it is serious limitation that such link format
does not support named link targets inside PDF files. Maybe the part
before second "::" could be considered as a named target
if it does not look like a number. I am unsure concerning search
strings containing "::", they may require more accurate regexp
or using e.g. percent encoding as in URLs.
#+begin_src emacs-lisp
(org-link-set-parameters
"pdf-pag"
:follow (lambda (path)
(let ((pag (if (string-match "::\\([1-9]+\\):*:*\\(.*\\)" path)
(format "--page=%s" (match-string 1 path))
(error "no pages")))
(clean-path (expand-file-name (replace-regexp-in-string "::.+"
"" path)))
(str (when (string-match "::\\([1-9]+\\)::\\(.+\\)" path)
(format "--find=%s" (match-string 2 path)))))
(if str
(start-process "zathura" nil "/usr/bin/zathura"
clean-path
pag
str)
(start-process "zathura" nil "/usr/bin/zathura"
clean-path
pag)))))
#+end_src
If your are asking my opinion on your function, I think that the
variant with start-process is a better one. There is a low level
alternative make-process but it requires more code, so it is less
convenient. As to the style of lisp code, I am not a proper
person to make suggestions.
I suspect that your function has a problem with page numbers like 10.
I do not like repetition of the regexp and tend to think that minor
variations are unintended. On the other hand a variant I could offer
is not shorter despite just one regexp and just one call of a
match function.
#+begin_src elisp
(defun wa-pdf-destination-zathura-args (target)
(let ((suffix (string-match
"::\\(?:\\([0-9]+\\)?\\(?:::\\(.+\\)\\)?\\|\\(.*\\)\\)$"
target)))
(if (not suffix)
(list (expand-file-name target))
(let* ((invalid (match-string 3 target))
(file (cond
((zerop suffix) (error "No file path in '%s'" target))
(invalid (error "Invalid destination within file: '%s'"
invalid))
(t (substring target 0 suffix))))
(page (match-string 1 target))
(search (match-string 2 target)))
(seq-remove #'null
(list (and page "--page") page
(and search "--find") search
(expand-file-name file)))))))
(defun wa-launch-pdf-viewer (target)
(let ((viewer "zathura")
(command (wa-pdf-destination-zathura-args target))
;; Do not allocate a pty. Really required only if the application
;; spawns background children and exits (xdg-open, gio open,
;; kde-open5), see Emacs Bug #44824.
(process-connection-type nil))
(apply #'start-process viewer "*Messages*" viewer command)))
#+end_src
#+begin_src elisp :results value list
(mapcar #'wa-pdf-destination-zathura-args
'(
"~/Download/grub.pdf::95::do"
"file.pdf::95"
"file.pdf::::do"
"file.pdf"
;; "::"
;; "::95"
;; "file.pdf::a"
;; "file.pdf::95:do"
))
#+end_src