rm interactive on org-ref-key-in-file
[org-ref.git] / org-ref.org
index fbff159..8852a84 100644 (file)
@@ -12,6 +12,20 @@ This document is an experiment at creating a literate program to provide similar
 4. Exportable links to LaTeX
 5. Utility functions for dealing with bibtex files and org-files
 
+Some additional features include
+1. Get minibuffer messages for the cite/ref/label link under point
+
+With helm integration (default) you can:
+
+1. C-c ] to insert a citation link
+  in helm-bibtex
+   - Enter to insert or append citation(s)
+   - C-u Enter to insert an alternative cite link
+   - C-u C-u Enter to replace the citation at point
+2. C-u C-c ] to insert a ref link with helm completion
+3. C-u C-u C-c ] to insert a label with completion
+4. M-x org-ref to get a helm completion buffer with link checks, utilities and export options
+
 ** Header
 #+BEGIN_SRC emacs-lisp :tangle org-ref.el
 ;;; org-ref.el --- setup bibliography, cite, ref and label org-mode links.
@@ -52,6 +66,7 @@ The only external require is reftex-cite
 (require 'reftex-cite)
 (require 'dash)
 (require 'helm)
+(require 'helm-config)
 (require 'helm-bibtex)
 #+END_SRC
 
@@ -128,8 +143,8 @@ There are some variables needed later to tell this library where you store your
 
 
 (defcustom org-ref-insert-cite-function
-  'helm-bibtex
-  "Function to call to insert citation links. The default is `helm-bibtex'. org-ref modifies helm-bibtex a little bit to give org-mode citations, and to reorder default actions. You may use `org-ref-insert-cite-link' if you like the reftex interface."
+  'org-ref-helm-insert-cite-link
+  "Function to call to insert citation links. The default is `org-ref-helm-insert-cite-link' which uses `helm-bibtex'. org-ref modifies helm-bibtex a little bit to give org-mode citations, and to reorder default actions. You may use `org-ref-insert-cite-link' if you like the reftex interface."
  :type 'function
  :group 'org-ref)
 
@@ -218,11 +233,15 @@ We setup reftex here. We use a custom insert cite link function defined here: [[
         ;; I do not remember why I put this next line in. It doesn't
         ;; work for org-files. Nothing very bad happens, but it gives
         ;; an annoying error. Commenting it out for now.
-         ;(reftex-parse-all)
+         ;(reftex-parse-all
         )
     (make-local-variable 'reftex-cite-format)
-    (setq reftex-cite-format 'org)
-    (define-key org-mode-map (kbd org-ref-insert-cite-key) org-ref-insert-cite-function))
+    (setq reftex-cite-format 'org))
+
+;; define key for inserting citations
+(define-key org-mode-map
+  (kbd org-ref-insert-cite-key)
+  org-ref-insert-cite-function)
 
 (add-hook 'org-mode-hook 'org-mode-reftex-setup)
 
@@ -259,6 +278,189 @@ You can define a new citation link like this:
 (org-ref-define-citation-link "citez" ?z)
 #+END_SRC
 
+** Messages for link at cursor
+Here we setup code that shows you a context message for the element under the cursor when emacs is idle.
+#+BEGIN_SRC emacs-lisp :tangle org-ref.el
+(defvar org-ref-message-timer nil
+  "Variable to store the link message timer in.")
+
+
+(defun org-ref-show-link-messages ()
+  "Turn on link messages. You will see a message in the
+minibuffer when on a cite, ref or label link."
+  (interactive)
+  (or org-ref-message-timer
+      (setq org-ref-message-timer
+           (run-with-idle-timer 0.5 t 'org-ref-link-message))))
+
+
+(defun org-ref-cancel-link-messages ()
+  "Stop showing messages in minibuffer when on a link."
+  (interactive)
+  (cancel-timer org-ref-message-timer)
+  (setq org-ref-message-timer nil))
+
+
+(when org-ref-show-citation-on-enter
+  (org-ref-show-link-messages))
+
+;; this approach caused the selected region to not be highlighted any more.
+; (add-hook 'post-command-hook 'org-ref-link-message))
+; (remove-hook 'post-command-hook 'org-ref-link-message))
+#+END_SRC
+
+** Messages for context under mouse pointer
+Sometimes, when reading a document, I actually use the mouse more than the cursor. This code enables the mouse cursor to trigger a message in the minibuffer about what is under the cursor. I run this on a timer.
+
+The basic idea here is to get the mouse position, and if we can determine there is a character that (point) can move to, we move (point) and run the org-ref-link-message function. Since this runs on a timer, we store the last mouse position, and only run the function when the mouse has moved to avoid getting messages every time the timer runs.
+
+#+BEGIN_SRC emacs-lisp :tangle org-ref.el
+(defvar org-ref-last-mouse-pos nil
+ "Stores last mouse position for use in `org-ref-mouse-message'.")
+
+(defun org-ref-can-move-p ()
+  "See if a character is under the mouse. If so return the position for `goto-char'."
+  (let* ((line (cddr org-ref-last-mouse-pos))
+        (col  (cadr org-ref-last-mouse-pos)))
+    (save-excursion
+      (goto-char (window-start))
+      (forward-line line)
+      (if
+         (> (- (line-end-position) (line-beginning-position)) col)
+         (progn  (forward-char col) (point))
+       nil))))
+
+
+(defun org-ref-mouse-message ()
+  "Display message for link under mouse cursor"
+  (interactive)
+  (when (not (equal (mouse-position) org-ref-last-mouse-pos))
+    (setq org-ref-last-mouse-pos (mouse-position))
+    (let ((p (org-ref-can-move-p)))
+      (when p
+         (save-excursion
+           (goto-char p)
+           (org-ref-link-message))))))
+
+
+(defvar org-ref-message-timer-mouse nil
+  "Store mouse timer.")
+
+
+(defvar org-ref-mouse-message-interval 0.5
+  "How often to run the mouse message timer in seconds")
+
+
+(defun org-ref-mouse-messages-on ()
+  "Turn on mouse messages."
+  (interactive)
+  (or org-ref-message-timer-mouse
+      (setq org-ref-message-timer-mouse
+           (run-at-time "0.5 sec"
+                        org-ref-mouse-message-interval
+                        'org-ref-mouse-message))))
+
+
+(defun org-ref-mouse-messages-off ()
+  "Turn off mouse messages"
+  (interactive)
+  (cancel-timer org-ref-message-timer-mouse)
+  (setq org-ref-message-timer-mouse nil)
+  (message "Mouse messages are off"))
+#+END_SRC
+
+#+RESULTS:
+: org-ref-mouse-messages-off
+
+** Color-coded links
+Here we make the org-ref links a different color.
+
+citations are green
+refs are blue
+labels are black
+
+mailto:john
+
+cite:sokalski-2012-optim-ta,zhang-2011-spatial-tio2,li-2012-heter-ceram,li-2013-photoc
+
+cite*:sokalski-2012-optim-ta,zhang-2011-spatial-tio2,li-2012-heter-ceram,li-2013-photoc
+
+citenum:sokalski-2012-optim-ta,zhang-2011-spatial-tio2,li-2012-heter-ceram,li-2013-photoc
+
+ref:test
+
+label:test
+
+#+BEGIN_SRC emacs-lisp :tangle org-ref.el
+(defcustom org-ref-colorize-links
+  t
+  "When non-nil, change colors of links"
+  :group 'org-ref)
+
+
+(defcustom org-ref-cite-color
+  "forest green"
+  "Color of cite like links"
+  :group 'org-ref)
+
+
+(defcustom org-ref-ref-color
+  "dark red"
+  "Color of ref like links"
+  :group 'org-ref)
+
+
+(defcustom org-ref-label-color
+  "black"
+  "Color of label links"
+  :group 'org-ref)
+
+
+(defvar org-ref-cite-re nil
+ "regexp for cite links")
+
+
+(setq org-ref-cite-re
+      (concat "\\(" (mapconcat
+                    (lambda (x)
+                      (replace-regexp-in-string "\*" "\\\\*" x)
+                      )
+                    org-ref-cite-types "\\|") "\\)"
+  ":\\([a-zA-Z0-9-_:]*,?\\)*"))
+
+
+(setq org-ref-label-re
+      "label:\\([a-zA-Z0-9-_:]*,?\\)*")
+
+
+(setq org-ref-ref-re
+      "ref:\\([a-zA-Z0-9-_:]*,?\\)*")
+
+
+(defface org-ref-cite-face
+  `((t (:inherit org-link :foreground ,org-ref-cite-color)))
+  "Color for cite-like links in org-ref.")
+
+
+(defface org-ref-label-face
+  `((t (:inherit org-link :foreground ,org-ref-label-color)))
+  "Color for ref links in org-ref.")
+
+
+(defface org-ref-ref-face
+  `((t (:inherit org-link :foreground ,org-ref-ref-color)))
+  "Face for ref links in org-ref.")
+
+
+(when org-ref-colorize-links
+  (highlight-regexp org-ref-cite-re 'org-ref-cite-face)
+  (highlight-regexp org-ref-label-re 'org-ref-label-face)
+  (highlight-regexp org-ref-ref-re 'org-ref-ref-face))
+#+END_SRC
+
+#+RESULTS:
+
+
 * Links
 Most of this library is the creation of functional links to help with references and citations.
 ** General utilities
@@ -447,7 +649,7 @@ This code provides some functions to generate a simple sorted bibliography in ht
 
 #+BEGIN_SRC emacs-lisp :tangle org-ref.el
 (defun org-ref-get-bibtex-keys ()
-  "return a list of unique keys in the buffer."
+  "Return a list of unique keys in the buffer."
   (let ((keys '()))
     (org-element-map (org-element-parse-buffer) 'link
       (lambda (link)
@@ -457,7 +659,9 @@ This code provides some functions to generate a simple sorted bibliography in ht
                (key
                 (org-ref-split-and-strip-string (plist-get plist ':path)))
              (when (not (-contains? keys key))
-               (setq keys (append keys (list key)))))))))
+               (setq keys (append keys (list key))))))))
+      ;; set with-affiliated to get keys in captions
+      nil nil nil t)
     ;; Sort keys alphabetically
     (setq keys (cl-sort keys 'string-lessp :key 'downcase))
     keys))
@@ -575,7 +779,6 @@ We use a link for the bibliography so that we can click on it to open the biblio
                     (let* ((bibfile)
                            ;; object is the link you clicked on
                            (object (org-element-context))
-
                            (link-string-beginning)
                            (link-string-end))
 
@@ -889,23 +1092,37 @@ In long documents, a list of figures is not uncommon. Here we create a clickable
 #+END_SRC
 ** label
 
-The label link provides a way to create labels in org-mode. We make it clickable because we want to make sure labels are unique. This code will tell you how many instances of a label are found.  We search for label links, LaTeX labels, and the org-mode format for labels. We probably should search for tblnames too.
-*************** TODO search tblnames, custom_ids and check for case sensitivity
-*************** END
+The label link provides a way to create labels in org-mode. We make it clickable because we want to make sure labels are unique. This code will tell you how many instances of a label are found.  We search for label links, LaTeX labels, and org-mode format for labels, tblnames too.
 
 #+BEGIN_SRC emacs-lisp  :tangle org-ref.el
+(defun org-ref-count-labels (label)
+  "Counts number of matches for label in the document"
+  (+ (count-matches (format "label:%s\\b[^-:]" label) (point-min) (point-max))
+     ;; for tblname, it is not enough to get word boundary
+     ;; tab-little and tab-little-2 match then.
+     (count-matches (format "^#\\+tblname:\\s-*%s\\b[^-:]" label) (point-min) (point-max))
+     (count-matches (format "\\label{%s}" label) (point-min) (point-max))
+     ;; this is the org-format #+label:
+     (count-matches (format "^#\\+label:\\s-*%s\\b[^-:]" label) (point-min) (point-max))
+     (let ((custom-id-count 0))
+       (org-map-entries
+       (lambda ()
+         (when (string= label (org-entry-get (point) "CUSTOM_ID"))
+           (setq custom-id-count (+ 1 custom-id-count)))))
+       custom-id-count)))
+
 (org-add-link-type
  "label"
  (lambda (label)
    "on clicking count the number of label tags used in the buffer. A number greater than one means multiple labels!"
-   (message (format "%s occurences"
-                   (+ (count-matches (format "label:%s\\b[^-:]" label) (point-min) (point-max) t)
-                       ;; for tblname, it is not enough to get word boundary
-                       ;; tab-little and tab-little-2 match then.
-                       (count-matches (format "^#\\+tblname:\\s-*%s\\b[^-:]" label) (point-min) (point-max) t)
-                      (count-matches (format "\\label{%s}\\b" label) (point-min) (point-max) t)
-                       ;; this is the org-format #+label:
-                      (count-matches (format "^#\\+label:\\s-*%s\\b[^-:]" label) (point-min) (point-max) t)))))
+   (let ((count (org-ref-count-labels label)))
+   (message (format "%s occurence%s"
+                   count
+                   (if (or (= count 0)
+                             (> count 1))
+                       "s"
+                     ""))
+                   (org-ref-count-labels label))))
  (lambda (keyword desc format)
    (cond
     ((eq format 'html) (format "(<label>%s</label>)" path))
@@ -1013,7 +1230,7 @@ It would be nice to use completion to enter a ref link, where a list of labels i
 
 #+BEGIN_SRC emacs-lisp :tangle org-ref.el
 (defun org-ref-get-org-labels ()
- "find #+LABEL: labels"
+ "Return a list of #+LABEL: labels."
   (save-excursion
     (goto-char (point-min))
     (let ((matches '()))
@@ -1024,7 +1241,7 @@ matches)))
 
 #+BEGIN_SRC emacs-lisp :tangle org-ref.el
 (defun org-ref-get-custom-ids ()
- "return a list of custom_id properties in the buffer"
+ "Return a list of custom_id properties in the buffer."
  (let ((results '()) custom_id)
    (org-map-entries
     (lambda ()
@@ -1049,6 +1266,7 @@ Finally, we get the table names.
 
 #+BEGIN_SRC emacs-lisp :tangle org-ref.el
 (defun org-ref-get-tblnames ()
+  "Return list of table names in the buffer."
   (org-element-map (org-element-parse-buffer 'element) 'table
     (lambda (table)
       (org-element-property :name table))))
@@ -1058,18 +1276,100 @@ Now, we can put all the labels together which will give us a list of candidates.
 
 #+BEGIN_SRC emacs-lisp  :tangle org-ref.el
 (defun org-ref-get-labels ()
-  "returns a list of labels in the buffer that you can make a ref link to. this is used to auto-complete ref links."
+  "Returns a list of labels in the buffer that you can make a ref link to.
+This is used to auto-complete ref links and in helm menus."
   (save-excursion
     (save-restriction
       (widen)
       (goto-char (point-min))
       (let ((matches '()))
-       (while (re-search-forward "label:\\([a-zA-z0-9:-]*\\)" (point-max) t)
+        ;; these are the label:stuff  kinds
+       (while (re-search-forward "[^#+]label:\\([a-zA-z0-9:-]*\\)" (point-max) t)
          (add-to-list 'matches (match-string-no-properties 1) t))
-       (append matches (org-ref-get-org-labels) (org-ref-get-latex-labels) (org-ref-get-tblnames) (org-ref-get-custom-ids))))))
+       (append matches
+               (org-ref-get-org-labels)
+               (org-ref-get-latex-labels)
+               (org-ref-get-tblnames)
+               (org-ref-get-custom-ids))))))
 #+END_SRC
 
-Now we create the completion function. This works from the org-machinery, e.g. if you type C-c C-l to insert a link, and use completion by pressing tab.
+Let us make a helm function to insert a label link. This will help you enter unique labels by showing matching labels until they are all gone and you are left with a unique one. If you are on a link, it means you want to replace it.
+#+BEGIN_SRC emacs-lisp :tangle org-ref.el
+(defun org-ref-helm-insert-label-link ()
+  "Insert a label link. helm just shows you what labels already exist.
+If you are on a label link, replace it."
+  (interactive)
+  (let* ((labels (org-ref-get-labels))
+        (cb (current-buffer)))
+    (helm :sources `(((name . "Existing labels")
+                     (candidates . ,labels)
+                     ;; default action is to open to the label
+                     (action . (lambda (label)
+                                 ;; unfortunately I do not have markers here
+                                 (org-open-link-from-string (format "ref:%s" label))))
+                     ;; if you select a label, replace current one
+                     (action . (lambda (label)
+                                 (switch-to-buffer ,cb)
+                                 (cond
+                                  ;;  no prefix or on a link
+                                  ((equal helm-current-prefix-arg nil)
+                                   (let* ((object (org-element-context))
+                                          (last-char (save-excursion
+                                                       (goto-char (org-element-property :end object))
+                                                       (backward-char)
+                                                       (if (looking-at " ")
+                                                           " "
+                                                         ""))))
+                                     (when (-contains? '("label")
+                                                       (org-element-property :type object))
+                                         ;; we are on a link, so replace it.
+                                       (setf
+                                          (buffer-substring
+                                           (org-element-property :begin object)
+                                           (org-element-property :end object))
+                                          (concat
+                                           (replace-regexp-in-string
+                                            (org-element-property :path object)
+                                            label
+                                            (org-element-property :raw-link object))
+                                           last-char)))))
+                                  ;; no prefix options defined
+                                  ))))
+                    ;; no matching selection creates a new label
+                    ((name . "Create new label")
+                     (dummy)
+                     ;; default action creates a new label, or replaces old one
+                     (action .  (lambda (label)
+                                  (switch-to-buffer ,cb)
+                                  (let* ((object (org-element-context))
+                                         (last-char (save-excursion
+                                                      (goto-char (org-element-property :end object))
+                                                      (backward-char)
+                                                      (if (looking-at " ")
+                                                          " "
+                                                        ""))))
+                                    (if (-contains? '("label")
+                                                    (org-element-property :type object))
+                                        ;; we are on a link, so replace it.
+                                        (setf
+                                         (buffer-substring
+                                          (org-element-property :begin object)
+                                          (org-element-property :end object))
+                                         (concat
+                                          (replace-regexp-in-string
+                                           (org-element-property :path object)
+                                           helm-pattern
+                                           (org-element-property :raw-link object))
+                                          last-char))
+                                      ;; new link
+                                      (insert
+                                       (concat
+                                        "label:"
+                                        (or label
+                                            helm-pattern))))))))))))
+#+END_SRC
+
+Now we create a completion function. This works from the org-machinery, e.g. if you type C-c C-l to insert a link, and use completion by pressing tab.
 
 #+BEGIN_SRC emacs-lisp  :tangle org-ref.el
 (defun org-ref-complete-link (&optional arg)
@@ -1087,6 +1387,89 @@ Alternatively, you may want to just call a function that inserts a link with com
  (insert (org-ref-complete-link)))
 #+END_SRC
 
+Another alternative ref insertion is to use helm.
+
+#+BEGIN_SRC emacs-lisp :tangle org-ref.el
+(defun org-ref-helm-insert-ref-link ()
+  "Helm menu to insert ref links to labels in the document.
+If you are on link, replace with newly selected label.
+Use C-u to insert a different kind of ref link.
+Use C-u C-u to insert a [[#custom-id]] link
+"
+  (interactive)
+  (let* ((labels (org-ref-get-labels))
+        (bs (buffer-string))
+        (contexts (with-temp-buffer
+                    (insert bs)
+                    (mapcar 'org-ref-get-label-context labels)))
+        (cb (current-buffer)))
+
+    (helm :input (thing-at-point 'word)
+         :sources `(((name . "Available labels to ref")
+                     (candidates . ,(loop for label in labels
+                                          for context in contexts
+                                          ;; we do some kludgy adding spaces
+                                          ;; and bars to make it "easier" to
+                                          ;; see in helm.
+                                          collect (cons (concat
+                                                         label "\n"
+                                                         (mapconcat
+                                                          (lambda (x)
+                                                            (concat "   |" x))
+                                                          (split-string context "\n")
+                                                          "\n"
+                                                          ) "\n\n") label)))
+                     ;; default action to replace or insert ref link.
+                     (action . (lambda (label)
+                                 (switch-to-buffer ,cb)
+
+                                 (cond
+                                  ;;  no prefix or on a link
+                                  ((equal helm-current-prefix-arg nil)
+                                   (let* ((object (org-element-context))
+                                          (last-char (save-excursion
+                                                       (goto-char (org-element-property :end object))
+                                                       (backward-char)
+                                                       (if (looking-at " ")
+                                                           " "
+                                                         ""))))
+                                     (if (-contains? '("ref" "eqref" "pageref" "nameref")
+                                                     (org-element-property :type object))
+                                         ;; we are on a link, so replace it.
+                                         (setf
+                                          (buffer-substring
+                                           (org-element-property :begin object)
+                                           (org-element-property :end object))
+                                          (concat
+                                           (replace-regexp-in-string
+                                            (org-element-property :path object)
+                                            label
+                                            (org-element-property :raw-link object))
+                                           last-char))
+                                       ;; insert a new link
+                                       (insert
+                                        (concat
+                                         "ref:" label))
+                                       )))
+                                  ;; one prefix, alternate ref link
+                                  ((equal helm-current-prefix-arg '(4))
+                                   (insert
+                                    (concat
+                                     (helm :sources '((name . "Ref link types")
+                                                      (candidates . ("ref" "eqref" "pageref" "nameref"))
+                                                      (action . (lambda (x) x))))
+                                     ":" label)))
+                                  ;; two prefixes, insert section custom-id link
+                                  ((equal helm-current-prefix-arg '(16))
+                                   (insert
+                                    (format "[[#%s]]" label)))
+                                  ))
+                             ))))))
+#+END_SRC
+
+#+RESULTS:
+: org-ref-helm-insert-ref-link
+
 ** pageref
 
 This refers to the page of a label in LaTeX.
@@ -1330,9 +1713,15 @@ Now, we can see if an entry is in a file.
 #+BEGIN_SRC emacs-lisp :tangle org-ref.el
 (defun org-ref-key-in-file-p (key filename)
   "determine if the key is in the file"
-  (interactive "skey: \nsFile: ")
   (save-current-buffer
     (let ((bibtex-files (list filename)))
+      ;; This is something I am trying because when the bibtex file is open, and
+      ;; you have added to it, the only way I find to get the update to update
+      ;; is to close it and reopen it. or to save it and revert it.
+      (when (get-file-buffer filename)
+       (set-buffer (get-file-buffer filename))
+       (save-buffer)
+       (revert-buffer t t))
       (bibtex-search-entry key t))))
 #+END_SRC
 
@@ -1725,7 +2114,25 @@ We will want to generate formatting functions for each citation type. The reason
         ;; bibtex format
        (concat "\\" ,type (when desc (org-ref-format-citation-description desc)) "{"
               (mapconcat (lambda (key) key) (org-ref-split-and-strip-string keyword) ",")
-              "}"))))))
+              "}")))
+      ;; for markdown we generate pandoc citations
+      ((eq format 'md)
+       (cond
+       (desc  ;; pre and or post text
+        (let* ((text (split-string desc "::"))
+               (pre (car text))
+               (post (cadr text)))
+          (concat
+           (format "[@%s," keyword)
+           (when pre (format " %s" pre))
+           (when post (format ", %s" post))
+           "]")))
+       (t
+        (format "[%s]"
+                (mapconcat
+                 (lambda (key) (concat "@" key))
+                 (org-ref-split-and-strip-string keyword)
+                 "; "))))))))
 #+END_SRC
 
 
@@ -2019,8 +2426,6 @@ And at the end of the document put \makeglossaries.
      (format "\\Glspl{%s}" path)))))
 #+END_SRC
 
-
-
 * Utilities
 ** create simple text citation from bibtex entry
 
@@ -2236,8 +2641,8 @@ Here is the python script for uploading.
 *************** TODO document how to get the cookies
 *************** END
 
-
-#+BEGIN_SRC python :tangle upload_bibtex_citeulike.py
+# :tangle upload_bibtex_citeulike.py
+#+BEGIN_SRC python
 #!python
 import pickle, requests, sys
 
@@ -2361,6 +2766,9 @@ If no bibliography is in the buffer the `reftex-default-bibliography' is used."
 #+END_SRC
 
 ** Find bad cite links
+   :PROPERTIES:
+   :ID:       8515E800-EDA0-4B2A-85FD-55B6FF849203
+   :END:
 Depending on how you enter citations, you may have citations with no corresponding bibtex entry. This function finds them and gives you a clickable table to navigate to them.
 
 #+BEGIN_SRC emacs-lisp  :tangle org-ref.el
@@ -2394,13 +2802,21 @@ Makes a new buffer with clickable links."
     (org-element-map (org-element-parse-buffer) 'link
       (lambda (link)
        (let ((plist (nth 1 link)))
-         (when (equal (plist-get plist ':type) "cite")
-           (dolist (key (org-ref-split-and-strip-string (plist-get plist ':path)) )
+         (when (-contains? org-ref-cite-types (plist-get plist :type))
+           (dolist (key (org-ref-split-and-strip-string (plist-get plist :path)))
              (when (not (index key bibtex-keys))
-               (setq bad-citations (append bad-citations
-                                           `(,(format "%s [[elisp:(progn (switch-to-buffer-other-frame \"%s\")(goto-char %s))][not found here]]\n"
-                                                      key (buffer-name)(plist-get plist ':begin)))))
-               ))))))
+               (message-box "%s" link)
+               (setq
+                bad-citations
+                (append
+                 bad-citations
+                 `(,(format "%s [[elisp:(progn (switch-to-buffer-other-frame \"%s\")(goto-char %s))][not found here]]\n"
+                            key
+                            (buffer-name)
+                            (plist-get plist :begin)))))
+               )))))
+      ;; set with-affilates to t to get citations in a caption
+      nil nil nil t)
 
     (if bad-citations
       (progn
@@ -2418,6 +2834,162 @@ Makes a new buffer with clickable links."
       (message "No bad cite links found"))))
 #+END_SRC
 
+** helm interface to org-ref
+In [[id:8515E800-EDA0-4B2A-85FD-55B6FF849203][Find bad cite links]] we wrote a function that finds bad links and creates a buffer of links to them.
+
+Here we develop a similar idea, but instead of an org-buffer with links, we create helm sources for bad cite links, bad ref links, and multiple labels.
+
+#+BEGIN_SRC emacs-lisp :tangle org-ref.el
+(defun org-ref-bad-cite-candidates ()
+  "Returns a list of conses (key . marker) where key does not exist in the known bibliography files, and marker points to the key."
+  (let* ((cp (point))                  ; save to return to later
+        (bibtex-files (org-ref-find-bibliography))
+         (bibtex-file-path (mapconcat
+                           (lambda (x)
+                             (file-name-directory (file-truename x)))
+                           bibtex-files ":"))
+        (bibtex-keys (mapcar (lambda (x) (car x))
+                             (bibtex-global-key-alist)))
+        (bad-citations '()))
+
+    (org-element-map (org-element-parse-buffer) 'link
+      (lambda (link)
+       (let ((plist (nth 1 link)))
+         (when (-contains? org-ref-cite-types (plist-get plist :type))
+           (dolist (key (org-ref-split-and-strip-string (plist-get plist :path)) )
+             (when (not (index key bibtex-keys))
+               (goto-char (plist-get plist :begin))
+               (re-search-forward key)
+               (push (cons key (point-marker)) bad-citations)))
+           )))
+      ;; add with-affiliates to get cites in caption
+      nil nil nil t)
+    (goto-char cp)
+    bad-citations))
+
+
+(defun org-ref-bad-ref-candidates ()
+  "Returns a list of conses (ref . marker) where ref is a ref link that does not point to anything (i.e. a label)."
+  ;; first get a list of legitimate labels
+  (let ((cp (point))
+       (labels (org-ref-get-labels))
+       (bad-refs '()))
+    ;; now loop over ref links
+    (goto-char (point-min))
+    (org-element-map (org-element-parse-buffer) 'link
+      (lambda (link)
+       (let ((plist (nth 1 link)))
+         (when (or  (equal (plist-get plist ':type) "ref")
+                    (equal (plist-get plist ':type) "eqref")
+                    (equal (plist-get plist ':type) "pageref")
+                    (equal (plist-get plist ':type) "nameref"))
+           (unless (-contains? labels (plist-get plist :path))
+             (goto-char (plist-get plist :begin))
+             (add-to-list
+              'bad-refs
+              (cons (plist-get plist :path)
+                    (point-marker))))))))
+    (goto-char cp)
+    bad-refs))
+
+
+(defun org-ref-bad-label-candidates ()
+  "Return a list of labels where label is multiply defined."
+  (let ((labels (org-ref-get-labels))
+       (multiple-labels '()))
+    (when (not (= (length labels)
+                 (length (-uniq labels))))
+      (dolist (label labels)
+       (when (> (-count (lambda (a)
+                          (equal a label))
+                        labels) 1)
+         ;; this is a multiply defined label.
+         (let ((cp (point)))
+           (goto-char (point-min))
+           (while (re-search-forward
+                   (format  "[^#+]label:%s\\s-" label) nil t)
+             (push (cons label (point-marker)) multiple-labels))
+
+           (goto-char (point-min))
+           (while (re-search-forward
+                   (format  "\\label{%s}\\s-?" label) nil t)
+             (push (cons label (point-marker)) multiple-labels))
+
+           (goto-char (point-min))
+           (while (re-search-forward
+                   (format  "^#\\+label:\\s-*%s" label) nil t)
+             (push (cons label (point-marker)) multiple-labels))
+
+           (goto-char (point-min))
+           (while (re-search-forward
+                   (format   "^#\\+tblname:\\s-*%s" label) nil t)
+             (push (cons label (point-marker)) multiple-labels))
+           (goto-char cp)))))
+      multiple-labels))
+#+END_SRC
+
+#+RESULTS:
+: org-ref-bad-label-candidates
+
+Now, we have a functions for candidates, we can make helm sources for each one, and then run a helm command to view them.
+
+#+BEGIN_SRC emacs-lisp :tangle org-ref.el
+(defun org-ref ()
+  "Opens a helm interface to actions for org-ref.
+Shows bad citations, ref links and labels"
+  (interactive)
+  (let ((cb (current-buffer))
+       (bad-citations (org-ref-bad-cite-candidates))
+       (bad-refs (org-ref-bad-ref-candidates))
+       (bad-labels (org-ref-bad-label-candidates)))
+
+    (helm :sources `(((name . "Bad citations")
+                      (candidates . ,bad-citations)
+                      (action . (lambda (marker)
+                                  (switch-to-buffer (marker-buffer marker))
+                                  (goto-char marker))))
+                    ;;
+                    ((name . "Bad Labels")
+                     (candidates . ,bad-labels)
+                     (action . (lambda (marker)
+                                  (switch-to-buffer (marker-buffer marker))
+                                  (goto-char marker))))
+                    ;;
+                    ((name . "Bad ref links")
+                     (candidates . ,bad-refs)
+                     (action . (lambda (marker)
+                                         (switch-to-buffer (marker-buffer marker))
+                                         (goto-char marker))))
+                    ;;
+                    ((name . "Utilities")
+                     (candidates . (("Check buffer again" . org-ref)
+                                    ("Insert citation" . helm-bibtex)
+                                    ("Insert label link" . org-ref-helm-insert-label-link)
+                                    ("Insert ref link" . org-ref-helm-insert-ref-link)
+                                    ("List of figures" . org-ref-list-of-figures)
+                                    ("List of tables" . org-ref-list-of-tables)
+                                    ("Table of contents" . nil)
+                                    ))
+                     (action . (lambda (x)
+                                 (switch-to-buffer ,cb)
+                                 (funcall x))))
+                    ;;
+                    ((name . "Export functions")
+                     (candidates . (("Extract cited entries" . org-ref-extract-bibtex-entries)
+                                    ("Export to html and open" . (lambda () (org-open-file (org-html-export-to-html))))
+                                    ("Export to pdf and open" . (lambda ()
+                                                                  (org-open-file (org-latex-export-to-pdf))))
+                                    ("Export to manuscript pdf and open" . ox-manuscript-export-and-build-and-open)
+                                    ("Export submission manuscript pdf and open" . ox-manuscript-build-submission-manuscript-and-open)
+
+                                    ))
+                     (action . (lambda (x)
+                                 (switch-to-buffer ,cb)
+                                 (funcall x))))
+                     ))))
+#+END_SRC
+
+
 ** Finding non-ascii characters
 I like my bibtex files to be 100% ascii. This function finds the non-ascii characters so you can replace them.
 
@@ -2648,6 +3220,151 @@ Sometimes it may be helpful to manually change the order of citations. These fun
 (add-hook 'org-shiftright-hook (lambda () (org-ref-swap-citation-link 1)))
 (add-hook 'org-shiftleft-hook (lambda () (org-ref-swap-citation-link -1)))
 #+END_SRC
+
+** Lightweight messages about links
+To get a lighter weight message about the label, ref and cite links, we define a function that gives us the minibuffer message, without the menu. We run this in an idle timer.
+
+#+BEGIN_SRC emacs-lisp :tangle org-ref.el
+(defun org-ref-get-label-context (label)
+  "Return a string of context around a label."
+  (save-excursion
+    (catch 'result
+      (goto-char (point-min))
+      (when (re-search-forward
+            (format "label:%s\\b" label) nil t)
+       (throw 'result (buffer-substring
+                       (progn
+                         (previous-line)
+                         (beginning-of-line)
+                         (point))
+                       (progn
+                         (forward-line 4)
+                         (point)))))
+
+      (goto-char (point-min))
+      (when (re-search-forward
+            (format "\\label{%s}" label) nil t)
+       (throw 'result (buffer-substring
+                       (progn
+                         (previous-line)
+                         (beginning-of-line)
+                         (point))
+                       (progn
+                         (forward-line 4)
+                         (point)))))
+
+      (goto-char (point-min))
+      (when (re-search-forward
+            (format "^#\\+label:\\s-*\\(%s\\)\\b" label) nil t)
+       (throw 'result (buffer-substring
+                       (progn
+                         (previous-line)
+                         (beginning-of-line)
+                         (point))
+                       (progn
+                         (forward-line 4)
+                         (point)))))
+
+      (goto-char (point-min))
+      (when (re-search-forward
+            (format "^#\\+tblname:\\s-*\\(%s\\)\\b" label) nil t)
+       (throw 'result (buffer-substring
+                       (progn
+                         (previous-line)
+                         (beginning-of-line)
+                         (point))
+                       (progn
+                         (forward-line 4)
+                         (point)))))
+      (throw 'result "!!! NO CONTEXT FOUND !!!"))))
+
+
+(defun org-ref-link-message ()
+  "Print a minibuffer message about the link that point is on."
+  (interactive)
+  (when (eq major-mode 'org-mode)
+    (let* ((object (org-element-context))
+          (type (org-element-property :type object)))
+      (save-excursion
+       (cond
+        ;; cite links
+        ((-contains? org-ref-cite-types type)
+         (message (org-ref-get-citation-string-at-point)))
+
+        ;; message some context about the label we are referring to
+        ((string= type "ref")
+         (message "%scount: %s"
+                  (org-ref-get-label-context
+                   (org-element-property :path object))
+                  (org-ref-count-labels
+                       (org-element-property :path object))))
+
+        ((string= type "eqref")
+         (message "%scount: %s"
+                  (org-ref-get-label-context
+                   (org-element-property :path object))
+                  (org-ref-count-labels
+                       (org-element-property :path object))))
+
+        ;; message the count
+        ((string= type "label")
+         (let ((count (org-ref-count-labels
+                       (org-element-property :path object))))
+           ;; get plurality on occurrence correct
+           (message (concat
+                     (number-to-string count)
+                     " occurence"
+                     (when (or (= count 0)
+                               (> count 1))
+                       "s")))))
+
+        ((string= type "custom-id")
+         (save-excursion
+           (org-open-link-from-string
+            (format "[[#%s]]" (org-element-property :path object)))
+           (message "%s" (org-get-heading))))
+
+         ;; check if the bibliography files exist.
+        ((string= type "bibliography")
+         (let* ((bibfile)
+                ;; object is the link you clicked on
+                (object (org-element-context))
+                (link-string (org-element-property :path object))
+                (link-string-beginning)
+                (link-string-end))
+           (save-excursion
+             (goto-char (org-element-property :begin object))
+             (search-forward link-string nil nil 1)
+             (setq link-string-beginning (match-beginning 0))
+             (setq link-string-end (match-end 0)))
+
+            ;; make sure we are in link and not before the :
+           (when (> link-string-beginning (point))
+             (goto-char link-string-beginning))
+
+           ;; now if we have comma separated bibliographies
+           ;; we find the one clicked on. we want to
+           ;; search forward to next comma from point
+           (save-excursion
+             (if (search-forward "," link-string-end 1 1)
+                 (setq key-end (- (match-end 0) 1)) ; we found a match
+               (setq key-end (point)))) ; no comma found so take the point
+
+           ;; and backward to previous comma from point
+           (save-excursion
+             (if (search-backward "," link-string-beginning 1 1)
+                 (setq key-beginning (+ (match-beginning 0) 1)) ; we found a match
+               (setq key-beginning (point)))) ; no match found
+           ;; save the key we clicked on.
+           (setq bibfile
+                 (org-ref-strip-string
+                  (buffer-substring key-beginning key-end)))
+           (if (file-exists-p bibfile)
+               (message "%s exists." bibfile)
+             (message "!!! %s NOT FOUND !!!" bibfile))))
+        )))))
+#+END_SRC
+
 * Aliases
 I like convenience. Here are some aliases for faster typing.
 
@@ -2692,56 +3409,129 @@ I like convenience. Here are some aliases for faster typing.
 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."
-  (let* ((object (org-element-context)))
+  "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)))
-      (goto-char link-string-end)
-      ;; sometimes there are spaces at the end of the link
-      ;; this code moves point pack until no spaces are there
-      (while (looking-back " ") (backward-char))
-      (insert (concat "," (mapconcat 'identity keys ","))))
+          (-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))
+       ;; and we want to go to the end of the new link
+       (goto-char
+        (org-element-property :end (org-element-context))))
+       (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)))))
+            (-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 org-ref-default-citation-link
+       (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 ",")))))))
+              (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 '("WOS" . "http://gateway.webofknowledge.com/gateway/Gateway.cgi?topic=%s&GWVersion=2&SrcApp=WEB&SrcAuth=HSB&DestApp=UA&DestLinkType=GeneralSearchSummary") 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)))
-    (save-excursion
-      (with-temp-buffer
-       (insert-file-contents bibfile)
-       (bibtex-search-entry key)
-       (org-ref-bib-citation)))))
+    (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.
-Check for pdf and doi, and add appropriate functions."
+  "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))
@@ -2759,23 +3549,35 @@ Check for pdf and doi, and add appropriate functions."
                  ;; I like this better than bibtex-url which does not always find
                  ;; the urls
                  (bibtex-autokey-get-field "doi"))))
-        (candidates `(                 ;;the first candidate is a brief summary
-                      ("Quit" . org-ref-citation-at-point)
+        (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))
 
-
-    (when (file-exists-p pdf-file)
+    ;; 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
-       '("Open pdf" . org-ref-open-pdf-at-point)
-       t
-       ))
+       '("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
@@ -2860,20 +3662,6 @@ This is a list of cons cells '((\"description\" . action)). The action function
 #+RESULTS:
 : org-ref-cite-click-helm
 
-To get a lighter weight message about the cite link, we define a function that gives us the minibuffer message, without the menu. We add it to a hook that updates after every command, including cursor movements.
-
-#+BEGIN_SRC emacs-lisp :tangle org-ref.el
-(defun org-ref-cite-link-p () (interactive)
-       (let* ((object (org-element-context))
-             (type (org-element-property :type object)))
-        ;;   We only want this to work on citation links
-        (when (-contains? org-ref-cite-types type)
-          (message (org-ref-get-citation-string-at-point)))))
-
-(when org-ref-show-citation-on-enter
- (add-hook 'post-command-hook 'org-ref-cite-link-p))
-#+END_SRC
-
 * End of code
 #+BEGIN_SRC emacs-lisp :tangle org-ref.el
 (provide 'org-ref)