+* Helm interface
+[[https://github.com/tmalsburg/helm-bibtex][helm-bibtex]] is a very cool interface to bibtex files. Out of the box though, it is not super convenient for org-ref. Here, we modify it to make it fit our workflow and extend it where needed.
+
+1. Make the default action to insert selected keys.
+2. Make open entry second action
+#+BEGIN_SRC emacs-lisp :tangle org-ref.el
+(setq helm-source-bibtex
+ '((name . "BibTeX entries")
+ (init . helm-bibtex-init)
+ (candidates . helm-bibtex-candidates)
+ (filtered-candidate-transformer . helm-bibtex-candidates-formatter)
+ (action . (("Insert citation" . helm-bibtex-insert-citation)
+ ("Show entry" . helm-bibtex-show-entry)
+ ("Open PDF file (if present)" . helm-bibtex-open-pdf)
+ ("Open URL or DOI in browser" . helm-bibtex-open-url-or-doi)
+ ("Insert reference" . helm-bibtex-insert-reference)
+ ("Insert BibTeX key" . helm-bibtex-insert-key)
+ ("Insert BibTeX entry" . helm-bibtex-insert-bibtex)
+ ("Attach PDF to email" . helm-bibtex-add-PDF-attachment)
+ ("Edit notes" . helm-bibtex-edit-notes)
+ ))))
+#+END_SRC
+
+Now, let us define a function that inserts the cite links:
+#+BEGIN_SRC emacs-lisp :tangle org-ref.el
+(defun helm-bibtex-format-org-ref (keys)
+ "Insert selected KEYS as cite link. Append KEYS if you are on a link.
+Technically, this function should return a string that is inserted by helm. This function does the insertion and gives helm an empty string to insert. This lets us handle appending to a link properly.
+
+In the helm-bibtex buffer, C-u will give you a helm menu to select a new link type for the selected entries.
+
+C-u C-u will change the key at point to the selected keys.
+"
+ (let* ((object (org-element-context))
+ (last-char (save-excursion
+ (goto-char (org-element-property :end object))
+ (backward-char)
+ (if (looking-at " ")
+ " "
+ ""))))
+ (cond
+ ;; case where we are in a link
+ ((and (equal (org-element-type object) 'link)
+ (-contains?
+ org-ref-cite-types
+ (org-element-property :type object)))
+ (cond
+ ;; no prefix. append keys
+ ((equal helm-current-prefix-arg nil)
+ (goto-char (org-element-property :end object))
+ (while (looking-back " ") (backward-char))
+ (insert (concat "," (mapconcat 'identity keys ","))))
+ ;; double prefix, replace key at point
+ ((equal helm-current-prefix-arg '(16))
+ (setf (buffer-substring
+ (org-element-property :begin object)
+ (org-element-property :end object))
+ (concat
+ (replace-regexp-in-string
+ (car (org-ref-get-bibtex-key-and-file)) ; key
+ (mapconcat 'identity keys ",") ; new keys
+ (org-element-property :raw-link object)
+ )
+ ;; replace space at end to avoid collapsing into next word.
+ last-char)))
+ (t
+ (message "Not found"))))
+
+ ;; We are next to a link, and we want to append
+ ;; next to a link means one character back is on a link.
+ ((save-excursion
+ (backward-char)
+ (and (equal (org-element-type (org-element-context)) 'link)
+ (-contains?
+ org-ref-cite-types
+ (org-element-property :type (org-element-context)))))
+ (while (looking-back " ") (backward-char))
+ (insert (concat "," (mapconcat 'identity keys ","))))
+
+ ;; insert fresh link
+ (t
+ ;;(message-box "fresh link")
+ (insert
+ (concat (if (equal helm-current-prefix-arg '(4))
+ (helm :sources `((name . "link types")
+ (candidates . ,org-ref-cite-types)
+ (action . (lambda (x) x))))
+ org-ref-default-citation-link)
+ ":"
+ (s-join "," keys))))))
+ ;; return empty string for helm
+ "")
+
+(setq helm-bibtex-format-citation-functions
+ '((org-mode . helm-bibtex-format-org-ref)))
+
+(defun org-ref-helm-insert-cite-link (arg)
+ "org-ref function to use helm-bibtex to insert a citation link.
+With one prefix arg, insert a ref link.
+With two prefix args, insert a label link."
+ (interactive "P")
+ (cond
+ ((equal arg nil)
+ (let ((helm-bibtex-bibliography (org-ref-find-bibliography)))
+ (helm-bibtex)))
+ ((equal arg '(4))
+ (org-ref-helm-insert-ref-link))
+ ((equal arg '(16))
+ (org-ref-helm-insert-label-link))))
+
+(require 'helm-bibtex)
+
+;; add our own fallback entries where we want them. These appear in reverse order of adding in the menu
+(setq helm-bibtex-fallback-options
+ (-insert-at 1 '("Crossref" . "http://search.crossref.org/?q=%s") helm-bibtex-fallback-options))
+
+(setq helm-bibtex-fallback-options
+ (-insert-at
+ 1
+ '("Scopus" . "http://www.scopus.com/scopus/search/submit/xadvanced.url?searchfield=TITLE-ABS-KEY(%s)")
+ helm-bibtex-fallback-options))
+
+(setq helm-bibtex-fallback-options
+ (-insert-at 1 '("Open Web of Science" . (lambda () (browse-url "http://apps.webofknowledge.com")))
+ helm-bibtex-fallback-options))
+#+END_SRC
+
+** A helm click menu
+This code provides a helm interface to things you can do when you click on a citation link. This is an alternative to the minibuffer menu.
+#+BEGIN_SRC emacs-lisp :tangle org-ref.el
+(defun org-ref-get-citation-string-at-point ()
+ "Get a string of a formatted citation"
+ (interactive)
+ (let* ((results (org-ref-get-bibtex-key-and-file))
+ (key (car results))
+ (bibfile (cdr results)))
+ (if bibfile
+ (save-excursion
+ (with-temp-buffer
+ (insert-file-contents bibfile)
+ (bibtex-search-entry key)
+ (org-ref-bib-citation)))
+ "!!! No entry found !!!" )))
+
+(defun org-ref-cite-candidates ()
+ "Generate the list of possible candidates for click actions on a cite link.
+Checks for pdf and doi, and add appropriate functions."
+ (interactive)
+ (let* ((results (org-ref-get-bibtex-key-and-file))
+ (key (car results))
+ (pdf-file (format (concat org-ref-pdf-directory "%s.pdf") key))
+ (bibfile (cdr results))
+ (url (save-excursion
+ (with-temp-buffer
+ (insert-file-contents bibfile)
+ (bibtex-search-entry key)
+ (bibtex-autokey-get-field "url"))))
+ (doi (save-excursion
+ (with-temp-buffer
+ (insert-file-contents bibfile)
+ (bibtex-search-entry key)
+ ;; I like this better than bibtex-url which does not always find
+ ;; the urls
+ (bibtex-autokey-get-field "doi"))))
+ (candidates `(("Quit" . org-ref-citation-at-point)
+ ("Open bibtex entry" . org-ref-open-citation-at-point))))
+ ;; for some reason, when there is no doi or url, they are returned as "". I
+ ;; prefer nil so we correct this here.
+ (when (string= doi "") (setq doi nil))
+ (when (string= url "") (setq url nil))
+
+ ;; Conditional pdf functions
+ (if (file-exists-p pdf-file)
+ (add-to-list
+ 'candidates
+ '("Open pdf" . org-ref-open-pdf-at-point)
+ t)
+ (add-to-list
+ 'candidates
+ '("Try to get pdf" . (lambda ()
+ (save-window-excursion
+ (org-ref-open-citation-at-point)
+ (bibtex-beginning-of-entry)
+ (doi-utils-get-bibtex-entry-pdf))))
+ t))
+
+
+ (add-to-list
+ 'candidates
+ '("Open notes" . org-ref-open-notes-at-point)
+ t)
+
+ ;; conditional url and doi functions
+ (when (or url doi)
+ (add-to-list
+ 'candidates
+ '("Open in browser" . org-ref-open-url-at-point)
+ t))
+
+ (when doi
+ (mapc (lambda (x)
+ (add-to-list 'candidates x t))
+ `(("WOS" . org-ref-wos-at-point)
+ ("Related articles in WOS" . org-ref-wos-related-at-point)
+ ("Citing articles in WOS" . org-ref-wos-citing-at-point)
+ ("Google Scholar" . org-ref-google-scholar-at-point)
+ ("Pubmed" . org-ref-pubmed-at-point)
+ ("Crossref" . org-ref-crossref-at-point)
+ )))
+
+ (add-to-list
+ 'candidates
+ '("Copy formatted citation to clipboard" . org-ref-copy-entry-as-summary)
+ t)
+
+ (add-to-list
+ 'candidates
+ '("Copy key to clipboard" . (lambda ()
+ (kill-new
+ (car (org-ref-get-bibtex-key-and-file)))))
+ t)
+
+ (add-to-list
+ 'candidates
+ '("Copy bibtex entry to file" . org-ref-copy-entry-at-point-to-file)
+ t)
+
+ (add-to-list
+ 'candidates
+ '("Email bibtex entry and pdf" . (lambda ()
+ (save-excursion
+ (org-ref-open-citation-at-point)
+ (email-bibtex-entry))))
+ t)
+ ;; finally return a numbered list of the candidates
+ (loop for i from 0
+ for cell in candidates
+ collect (cons (format "%2s. %s" i (car cell))
+ (cdr cell)))))
+
+
+(defvar org-ref-helm-user-candidates '()
+ "List of user-defined candidates to act when clicking on a cite link.
+This is a list of cons cells '((\"description\" . action)). The action function should not take an argument, and should assume point is on the cite key of interest.
+")
+
+;; example of adding your own function
+(add-to-list
+ 'org-ref-helm-user-candidates
+ '("Example" . (lambda () (message-box "You did it!")))
+ t)
+
+(defun org-ref-cite-click-helm (key)
+ "subtle points.
+1. get name and candidates before entering helm because we need the org-buffer.
+2. switch back to the org buffer before evaluating the action. most of them need the point and buffer."
+ (interactive)
+ (let ((name (org-ref-get-citation-string-at-point))
+ (candidates (org-ref-cite-candidates))
+ (cb (current-buffer)))
+
+ (helm :sources `(((name . ,name)
+ (candidates . ,candidates)
+ (action . (lambda (f)
+ (switch-to-buffer cb)
+ (funcall f))))
+ ((name . "User functions")
+ (candidates . ,org-ref-helm-user-candidates)
+ (action . (lambda (f)
+ (switch-to-buffer cb)
+ (funcall f))))
+ ))))
+#+END_SRC
+
+#+RESULTS:
+: org-ref-cite-click-helm
+