+** 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)))
+ ))))
+ (goto-char cp)
+ bad-citations))
+
+;; It seems I forgot I already defined this earlier!
+;; (defun org-ref-get-labels ()
+;; "Returns a list of known labels in the org document. These include label links, latex labels, label tags, and table names. The list contains all labels, not just unique ones.
+;; "
+;; (let ((cp (point))
+;; (labels '()))
+;; (goto-char (point-min))
+;; (while (re-search-forward "[^#+]label:\\(.*\\)\\s-" nil t)
+;; (push (match-string 1) labels))
+
+;; (goto-char (point-min))
+;; (while (re-search-forward "\\label{\\(.*\\)}\\s-?" nil t)
+;; (push (match-string 1) labels))
+
+;; (goto-char (point-min))
+;; (while (re-search-forward "^#\\+label:\\s-*\\(.*\\)" nil t)
+;; (push (match-string 1) labels))
+
+;; (goto-char (point-min))
+;; (while (re-search-forward "^#\\+tblname:\\s-*\\(.*\\)" nil t)
+;; (push (match-string 1) labels))
+;; ;; check for CUSTOM_ID
+;; (org-map-entries
+;; (lambda ()
+;; (when (org-entry-get (point) "CUSTOM_ID")
+;; (push (org-entry-get (point) "CUSTOM_ID") labels))))
+;; ;; return to original place
+;; (goto-char cp)
+;; labels))
+
+
+(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
+
+