Popup tips on bibtex links in org-mode

| categories: uncategorized | tags:

I want to explore using popup tips to display richer information about org-mode links. The idea is to have something like a tooltip that displays the bibtex entry when you hover over it, or click on it.

https://github.com/auto-complete/popup-el/blob/master/popup.el

Here is a canonical example of a popup.

(popup-tip "Hello, World!")
t

All I need to do is figure out a simple way to get the bibtex entry as a string, and pop it up when a link is clicked on.

(org-add-link-type
 "test"
 ;; this function is run when you click
 (lambda (link-string) 
   (popup-tip link-string))
 ;; formatting
(lambda (keyword desc format)
   (cond
    ((eq format 'html) (format "<pre>%s:%s</pre>" keyword desc)))))
lambda (link-string) (popup-tip link-string)
lambda (keyword desc format) (cond ((eq format (quote html)) (format <pre>%s:%s</pre> keyword desc)))

Now we give it a try.

test:show-me-the-popup

That looks good.

Ok, the penultimate step will be to lookup a bibtex entry, and show the entry in a popup. We will hardcode the path to the bibtex file.

(org-add-link-type
 "test"
 ;; this function is run when you click
 (lambda (bibtex-key)
   (let ((entry (with-temp-buffer
                  (insert-file-contents "~/Dropbox/bibliography/references.bib")
                  (goto-char (point-min))
                  (re-search-forward bibtex-key)
                  (bibtex-narrow-to-entry)
                  (buffer-string))))
     (popup-tip entry))))
lambda (bibtex-key) (let ((cb (current-buffer)) (entry (with-temp-buffer (insert-file-contents ~/Dropbox/bibliography/references.bib) (goto-char (point-min)) (re-search-forward bibtex-key) (bibtex-narrow-to-entry) (buffer-string)))) (popup-tip entry))

test:mehta-2014-ident-poten

And here is what appears for me:

The final step is to connect this to an idle timer . We want a popup to occur when our mouse is idle. I am setting this up to run one time, after 5 seconds of idleness.

(run-with-idle-timer 5 nil (lambda () (popup-tip "You are being idle")))
[nil 0 5 0 nil (lambda nil (popup-tip "You are being idle")) nil idle 0]

So, we need to setup an idle timer that runs on some interval. When the cursor is on the right kind of link, we want to get a popup. I adapted the following code from http://www.emacswiki.org/emacs/IdleTimers .

;; variable for the timer object
(defvar idle-timer-bibtex-timer nil)

;; callback function 
(defun idle-timer-bibtex-callback ()
  "displays a popup of the bibtex entry in a test link"
  (interactive)
  (let ((object (org-element-context)))    
    (when (and (equal (org-element-type object) 'link) 
               (equal (org-element-property :type object) "test"))
      (let* ((bibtex-key (org-element-property :path object))
             (entry (with-temp-buffer
                      (insert-file-contents "~/Dropbox/bibliography/references.bib")
                      (goto-char (point-min))
                      (re-search-forward bibtex-key)
                      (bibtex-narrow-to-entry)
                      (buffer-string))))
        (popup-tip entry)))))

;; start functions
(defun idle-timer-bibtex-start ()
  (interactive)
  (when (timerp idle-timer-bibtex-timer)
    (cancel-timer idle-timer-bibtex-timer))
  (setq idle-timer-bibtex-timer
          (run-with-timer 1 1 #'idle-timer-bibtex-callback)))

;; stop function
(defun idle-timer-bibtex-stop ()
  (interactive)
  (when (timerp idle-timer-bibtex-timer)
    (cancel-timer idle-timer-bibtex-timer))
  (setq idle-timer-bibtex-timer nil))

(idle-timer-bibtex-start)
idle-timer-bibtex-stop

test:kitchin-2008-alloy

Now, whenever the cursor is on the link, and there is an idle of about a sec, I get a popup window of the bibtex entry. It looks like this:

There are still some limitations to this code. It does not handle multiple citations in a link (like the cite links I normally use do). That will take a little work to fixup. I cannot figure out how to get mouse-over tooltips; this only works when the cursor is on the link. I do not know what the optimal timer setting is. This one runs every second. I do not see any issues in performance with that. Another issue might be making the timer a file local variable. It would be nice if the timer quit running when the file was closed. I do not know how easy that would be to implement, or if there should be one timer running for org-mode. Finally, this code is hard-coded to use my reference file. For a real module, we would probably provide some customization to choose other bibtex files. Overall though, this might be a handy way to quickly peruse the citations in an org-file.

Copyright (C) 2014 by John Kitchin. See the License for information about copying.

org-mode source

Org-mode version = 8.2.5h

Discuss on Twitter