tmalsburg/helm-bibtex

ivy-bibtex: Open with Evince as additional action

Closed this issue · 27 comments

Oftentimes, I need to open a PDF with Evince instead of within Emacs (which is perfect as the default though). I wish to add an action which does specifically this. I understand I need to do something like this:

(defun bibtex-completion-pdf-open-with-evince
  (lambda (fpath)
    (call-process "evince" nil 0 nil fpath)))

(ivy-bibtex-ivify-action bibtex-completion-pdf-open-with-evince ivy-bibtex-pdf-open-with-evince)

(ivy-add-actions
   'ivy-bibtex
   '(("P" ivy-bibtex-pdf-open-with-evince "Open PDF with Evince")))

i.e. defining a new function bibtex-completion-pdf-open-with-evince, then make it an ivy function (here ivy-bibtex-pdf-open-with-evince), and finally add it to the actions available for ivy-bibtex.

Obviously my code above does not work, and I think it is because of the definition of the initial function (for lack of knowledge, I basically copy-pasted the function provided in the doc to use Evince by default). Note that it does not appear at all in "Other actions" with ivy-bibtex, so maybe I'm doing something else wrong.

Thank you for your help and suggestions!

jagrg commented

That was the trick for the function, thanks!

However, I still cannot get it to work: the action does not appear in the list, and "P is not bound" if I try to launch it nevertheless… Am I missing something?

jagrg commented

@jagrg's solution looks good. Here's another solution (not tested) that recycles more of the existing code for opening PDFs. One benefit is that it works with multiple selected entries (not sure whether ivy even supports that).

(defun bibtex-completion-open-pdf-external (keys &optional fallback-action)
  (let ((bibtex-completion-pdf-open-function
         (lambda (fpath) (start-process "evince" "*helm-bibtex-evince*" "/usr/bin/evince" fpath))))
    (bibtex-completion-open-pdf keys fallback-action)))

(ivy-bibtex-ivify-action bibtex-completion-open-pdf-external ivy-bibtex-open-pdf-external)

(ivy-add-actions
 'ivy-bibtex
 '(("P" ivy-bibtex-open-pdf-external "Open PDF file in external viewer (if present)")))

I'm a little bit confused with what is going on… If I use ivy-bibtex-ivify-action (as in @tmalsburg's solution), it throws an error on Emacs startup:

Symbol's function definition is void: ivy-bibtex-ivify-action

If I go straight to ivy-add-actions with bibtex-completion-pdf-open-with-evince (as in @jagrg's answer), nothing at all happens with the message:

P is not bound

and this does not appear in the actions anyway.

This is with ivy-bibtex from MELPA (ivy-bibtex-20181030.2142), which I just reinstalled, and a pretty minimal .emacs simply to init ivy.

I would try adding a trivial dummy action to see whether that works. If not, I would ask the Ivy developers for help.

Hi @tmalsburg, I am still confused with the role of ivy-bibtex-ivify-action. If I use a simple example (hopefully… this is still beyond my limited Lisp skills):

(defun say-hello ()
   "Says hello."
   (interactive)
   (message "Hello, World!"))

(ivy-bibtex-ivify-action say-hello ivy-bibtex-say-hello)

(ivy-add-actions
   'ivy-bibtex
   '(("P" ivy-bibtex-say-hello "Say Hello")))

I still get a Symbol's value as variable is void: say-hello error message on startup. Skipping ivy-bibtex-ivify-action altogether:

(defun say-hello ()
   "Says hello."
   (interactive)
   (message "Hello, World!"))

(ivy-add-actions
   'ivy-bibtex
   '(("P" say-hello "Say Hello")))

Still does nothing (i.e. the action does not appear). Before I go on with Ivy developers, could you clarify for me the role of ivy-bibtex-ivify-action? Is it necessary to use it before adding an action?

jagrg commented

Re ivy-bibtex-ivify-action: Actions for helm and ivy look slightly different and the ivyfy/helmify macros simply adapt a generic actions such that they work with ivy and helm. This way, the function bibtex-completion-open-pdf-external can be used with ivy and helm. See also the documentation of the macro ivy-bibtex-ivify-action.

Hi, how extend this action to Helm-bibtex? I want to open my PDF file with Pdf-tools and Evince. Due to efficiency and speed,I sometimes would like to use Evince instead of Pdf-tools.

Thanks @tmalsburg for the additional explanations. There has been some progress here, following the suggestion from @jagrg, I tried his function and it did work as expected with Swiper. However, adapting it to ivy-bibtex does not add the action:

(defun say-hello (_)
  (message "Hello, World!"))

(ivy-add-actions
   'ivy-bibtex
   '(("P" ivy-bibtex-pdf-open-with-evince "Open PDF with Evince")))
jagrg commented

I add the following codes to my config file:

(defun bibtex-completion-open-pdf-external (keys &optional fallback-action)
  (let ((bibtex-completion-pdf-open-function
         (lambda (fpath) (start-process "evince" "*helm-bibtex-zathura*" "/usr/bin/zathura" fpath))))
    (bibtex-completion-open-pdf keys fallback-action)))

(helm-add-action-to-source
 "Zathura (PDF)" 'bibtex-completion-open-pdf-external
 helm-source-bibtex 1)

But it returns an error as follows:

setq: Wrong type argument: listp, "chung-2009-intrin-image"

How to solve it?

jagrg commented

It does not work!
Eager macro-expansion failure: (error "Malformed arglist: ((list keys) &optional fallback-action)") [2 times]
Malformed arglist: ((list keys) &optional fallback-action)

It seems to does work. But when loading init.el file, it have an error:
Symbol's function definition is void: helm-add-action-to-source

jagrg commented

@jagrg, not sure I'm making any progress here. With a very minimal init file (complete setup below), I still don't get anything (GNU Emacs 25.1.1, ivy-20181213.1650, ivy-bibtex-20181030.2142, both from MELPA):

(package-initialize)

(ivy-mode 1)

(setq
 bibtex-completion-bibliography '("/home/mathieu/Work/Biblio/BiblioMB.bib")
 bibtex-completion-library-path '("/home/mathieu/Work/Biblio/PDF/")
 )

(defun say-hello (_)
  (message "Hello, World!"))

(ivy-add-actions
   'ivy-bibtex
   '(("P" say-hello "Say Hello")))

(global-set-key (kbd "C-c b") 'ivy-bibtex)

Any idea?

jagrg commented

That was it… so simple. Thanks @jagrg for the tip!

Now a minor problem is that the list that shows in the minibuffer is truncated: basically, the last option ("P: Open PDF file in external viewer") is added at the end, but the minibuffer is not higher… and the first one ("p: Open PDF file") gets excluded. The list starts with the actual second option ("u: Open URL or DOI…"). The "p" option is still active though, only not visible.

Is it possible to increase the size of the minibuffer in this case?

jagrg commented

Turns out it was even lower-level than that: Emacs sets a higher limit for the "mini-windows" (minibuffer + echo area), with a default of 0.25. Adding:

(setq max-mini-window-height 0.30)

fixed the problem on my relatively small screen… I'm closing this issue, which is now completely solved.

Thanks for the update, Mathieu. And many thanks to Jonathan for your help. Shall we add a recipe for this to the documentation? It seems that other users might be interested in this as well. If you could create a PR for README.org that would be perfect.

Sure thing! Where would you have that? "Advanced usage (a.k.a. hacks)" section? Or as an example in "Create new actions" section? Not sure about the best fit.

Advanced usage is fine for now. I can move it somewhere more appropriate when I restructure the documentation. Thank you!

My apologize for taking so long for such a simple task… Anyway, the PR is up for you to review. I simply added the code working for ivy-bibtex (with a note about it), as I don't use helm-bibtex myself.

PR is here: #284

@basille I met the same problem and your settings fixed that. Thanks!