]> git.donarmstrong.com Git - org-ref.git/blob - org-ref.el
remove empty links and doi
[org-ref.git] / org-ref.el
1 ;;; org-ref.el --- cite and cross-reference in org-mode
2
3 ;; Copyright(C) 2014 John Kitchin
4
5 ;; Author: John Kitchin <jkitchin@andrew.cmu.edu>
6 ;; URL: https://github.com/jkitchin/org-ref
7 ;; Version: 0.2
8 ;; Keywords: org-mode, cite, ref, label
9 ;; Package-Requires: ((org) (dash) (helm) (helm-bibtex) (hydra))
10
11 ;; This file is not currently part of GNU Emacs.
12
13 ;; This program is free software; you can redistribute it and/or
14 ;; modify it under the terms of the GNU General Public License as
15 ;; published by the Free Software Foundation; either version 2, or (at
16 ;; your option) any later version.
17
18 ;; This program is distributed in the hope that it will be useful, but
19 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21 ;; General Public License for more details.
22
23 ;; You should have received a copy of the GNU General Public License
24 ;; along with this program ; see the file COPYING.  If not, write to
25 ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
26 ;; Boston, MA 02111-1307, USA.
27
28 ;;; Commentary:
29 ;;
30 ;; Lisp code to setup bibliography cite, ref and label org-mode links.
31 ;; also sets up reftex and helm for org-mode citations.  The links are
32 ;; clickable and do things that are useful.  You should really read
33 ;; org-ref.org for details.
34 ;;
35
36 ;;; Code:
37
38 (require 'reftex-cite)
39 (require 'dash)
40 (require 'helm)
41 (require 'helm-config)
42 (require 'helm-bibtex)
43 (require 'org)
44
45 ;; * Custom variables
46 (defgroup org-ref nil
47   "Customization group for org-ref.")
48
49 (defcustom org-ref-bibliography-notes
50   nil
51   "Filename where you will put all your notes about an entry in the default bibliography."
52   :type 'file
53   :group 'org-ref)
54
55 (defcustom org-ref-default-bibliography
56   nil
57   "List of bibtex files to search for.
58 You should use full-paths for each file."
59   :type '(repeat :tag "List of bibtex files" file)
60   :group 'org-ref)
61
62 (defcustom org-ref-pdf-directory
63   nil
64   "Directory where pdfs are stored by key.  put a trailing / in."
65   :type 'directory
66   :group 'org-ref)
67
68 (defcustom org-ref-default-citation-link
69   "cite"
70   "The default type of citation link to use."
71   :type 'string
72   :group 'org-ref)
73
74 (defcustom org-ref-insert-cite-key
75   "C-c ]"
76   "Keyboard shortcut to insert a citation."
77   :type 'string
78   :group 'org-ref)
79
80 (defcustom org-ref-bibliography-entry-format
81   '(("article" . "%a, %t, <i>%j</i>, <b>%v(%n)</b>, %p (%y). <a href=\"%U\">link</a>. <a href=\"http://dx.doi.org/%D\">doi</a>.")
82
83     ("book" . "%a, %t, %u (%y).")
84
85     ("proceedings" . "%e, %t in %S, %u (%y).")
86
87     ("inproceedings" . "%a, %t, %p, in %b, edited by %e, %u (%y)"))
88
89   "String to format an entry.  Just the reference, no numbering at the beginning, etc... see the `org-ref-reftex-format-citation' docstring for the escape codes."
90   :type 'string
91   :group 'org-ref)
92
93 (defcustom org-ref-open-notes-function
94   (lambda ()
95     (org-show-entry)
96     (show-branches)
97     (show-children)
98     (org-cycle '(64))
99     ;;(org-tree-to-indirect-buffer)
100     (outline-previous-visible-heading 1)
101     (recenter-top-bottom 0))
102   "User-defined way to open a notes entry.  This is excecuted after the entry is found, with the cursor at the beginning of the headline.  The default setting fully expands the notes, and moves the headline to the top of the buffer."
103 :type 'function
104 :group 'org-ref)
105
106
107 (defcustom org-ref-open-pdf-function
108    'org-ref-open-pdf-at-point
109 "User-defined function to open a pdf from a link.  The function must get the key at point, and derive a path to the pdf file, then open it.  The default function is `org-ref-open-pdf-at-point'."
110   :type 'function
111   :group 'org-ref)
112
113
114 (defcustom org-ref-insert-cite-function
115   'org-ref-helm-insert-cite-link
116   "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."
117  :type 'function
118  :group 'org-ref)
119
120
121 (defcustom org-ref-cite-onclick-function
122   'org-ref-cite-click-helm
123   "Function that runs when you click on a cite link.  The function must take no arguments.  You may also use `org-ref-cite-onclick-minibuffer-menu' if you do not like helm.  If you like `hydra', consider using `org-ref-cite-hydra'."
124  :type 'function
125  :group 'org-ref)
126
127
128 (defcustom org-ref-show-citation-on-enter t
129   "If non-nil add a hook function to show the citation summary in the minibuffer."
130  :group 'org-ref)
131
132 (defcustom org-ref-cite-types
133   '("cite" "nocite" ;; the default latex cite commands
134     ;; natbib cite commands, http://ctan.unixbrain.com/macros/latex/contrib/natbib/natnotes.pdf
135     "citet" "citet*" "citep" "citep*"
136     "citealt" "citealt*" "citealp" "citealp*"
137     "citenum" "citetext"
138     "citeauthor" "citeauthor*"
139     "citeyear" "citeyear*"
140     "Citet" "Citep" "Citealt" "Citealp" "Citeauthor"
141     ;; biblatex commands
142     ;; http://ctan.mirrorcatalogs.com/macros/latex/contrib/biblatex/doc/biblatex.pdf
143     "Cite"
144     "parencite" "Parencite"
145     "footcite" "footcitetext"
146     "textcite" "Textcite"
147     "smartcite" "Smartcite"
148     "cite*" "parencite*" "supercite"
149     "autocite" "Autocite" "autocite*" "Autocite*"
150     "Citeauthor*"
151     "citetitle" "citetitle*"
152     "citedate" "citedate*"
153     "citeurl"
154     "fullcite" "footfullcite"
155     ;; "volcite" "Volcite" cannot support the syntax
156     "notecite" "Notecite"
157     "pnotecite" "Pnotecite"
158     "fnotecite"
159     ;; multicites. Very limited support for these.
160     "cites" "Cites" "parencites" "Parencites"
161     "footcites" "footcitetexts"
162     "smartcites" "Smartcites" "textcites" "Textcites"
163     "supercites" "autocites" "Autocites"
164     ;; for the bibentry package
165     "bibentry"
166     )
167   "List of citation types known in `org-ref'."
168   :type '(repeat :tag "List of citation types" string)
169   :group 'org-ref)
170
171 (defcustom org-ref-clean-bibtex-entry-hook nil
172   "Hook that is run in `org-ref-clean-bibtex-entry'.  The functions should take no arguments, and operate on the bibtex entry at point."
173   :group 'org-ref
174   :type 'hook)
175
176 (defvar org-ref-bibliography-files
177   nil
178   "Variable to hold bibliography files to be searched.")
179
180 ;; * org-mode / reftex setup
181 (require 'reftex)
182 (defun org-mode-reftex-setup ()
183   "Setup `org-mode' and reftex for org-ref."
184     (and (buffer-file-name)
185          (file-exists-p (buffer-file-name))
186          (global-auto-revert-mode t))
187     (make-local-variable 'reftex-cite-format)
188     (setq reftex-cite-format 'org))
189
190 ;; define key for inserting citations
191 (define-key org-mode-map
192   (kbd org-ref-insert-cite-key)
193   org-ref-insert-cite-function)
194
195 (add-hook 'org-mode-hook 'org-mode-reftex-setup)
196
197 (eval-after-load 'reftex-vars
198   '(progn
199       (add-to-list 'reftex-cite-format-builtin
200                    '(org "Org-mode citation"
201                          ((?\C-m . "cite:%l")     ; default
202                           (?d . ",%l")            ; for appending
203                           (?a . "autocite:%l")
204                           (?t . "citet:%l")
205                           (?T . "citet*:%l")
206                           (?p . "citep:%l")
207                           (?P . "citep*:%l")
208                           (?h . "citeauthor:%l")
209                           (?H . "citeauthor*:%l")
210                           (?y . "citeyear:%l")
211                           (?x . "citetext:%l")
212                           (?n . "nocite:%l")
213                           )))))
214
215 ;; * Messages for link at cursor
216 (defvar org-ref-message-timer nil
217   "Variable to store the link message timer in.")
218
219
220 (defun org-ref-show-link-messages ()
221   "Turn on link messages.
222 You will see a message in the minibuffer when on a cite, ref or label link."
223   (interactive)
224   (or org-ref-message-timer
225       (setq org-ref-message-timer
226             (run-with-idle-timer 0.5 t 'org-ref-link-message))))
227
228
229 (defun org-ref-cancel-link-messages ()
230   "Stop showing messages in minibuffer when on a link."
231   (interactive)
232   (cancel-timer org-ref-message-timer)
233   (setq org-ref-message-timer nil))
234
235
236 (when org-ref-show-citation-on-enter
237   (org-ref-show-link-messages))
238
239 ;; ** Messages for context under mouse pointer
240
241 (defvar org-ref-last-mouse-pos nil
242  "Stores last mouse position for use in `org-ref-mouse-message'.")
243
244 (defun org-ref-can-move-p ()
245   "See if a character is under the mouse.  If so return the position for `goto-char'."
246   (let* ((line (cddr org-ref-last-mouse-pos))
247          (col  (cadr org-ref-last-mouse-pos)))
248     (save-excursion
249       (goto-char (window-start))
250       (forward-line line)
251       (if
252           (> (- (line-end-position) (line-beginning-position)) col)
253           (progn  (forward-char col) (point))
254         nil))))
255
256
257 (defun org-ref-mouse-message ()
258   "Display message for link under mouse cursor."
259   (interactive)
260   (when (not (equal (mouse-position) org-ref-last-mouse-pos))
261     (setq org-ref-last-mouse-pos (mouse-position))
262     (let ((p (org-ref-can-move-p)))
263       (when p
264           (save-excursion
265             (goto-char p)
266             (org-ref-link-message))))))
267
268
269 (defvar org-ref-message-timer-mouse nil
270   "Store mouse timer.")
271
272
273 (defvar org-ref-mouse-message-interval 0.5
274   "How often to run the mouse message timer in seconds.")
275
276
277 (defun org-ref-mouse-messages-on ()
278   "Turn on mouse messages."
279   (interactive)
280   (or org-ref-message-timer-mouse
281       (setq org-ref-message-timer-mouse
282             (run-at-time "0.5 sec"
283                          org-ref-mouse-message-interval
284                          'org-ref-mouse-message))))
285
286
287 (defun org-ref-mouse-messages-off ()
288   "Turn off mouse messages."
289   (interactive)
290   (cancel-timer org-ref-message-timer-mouse)
291   (setq org-ref-message-timer-mouse nil)
292   (message "Mouse messages are off"))
293
294 ;; Colorizing org-ref links
295 (defcustom org-ref-colorize-links
296   t
297   "When non-nil, change colors of links."
298   :group 'org-ref)
299
300
301 (defcustom org-ref-cite-color
302   "forest green"
303   "Color of cite like links."
304   :group 'org-ref)
305
306
307 (defcustom org-ref-ref-color
308   "dark red"
309   "Color of ref like links."
310   :group 'org-ref)
311
312
313 (defcustom org-ref-label-color
314   "dark magenta"
315   "Color of label links."
316   :group 'org-ref)
317
318
319 (defvar org-ref-cite-re nil
320  "Regexp for cite links.")
321
322
323 (setq org-ref-cite-re
324       (concat "\\(" (mapconcat
325                      (lambda (x)
326                        (replace-regexp-in-string "\*" "\\\\*" x)
327                        )
328                      org-ref-cite-types "\\|") "\\)"
329   ":\\([a-zA-Z0-9-_:\\./]*,?\\)*"))
330
331
332 (setq org-ref-label-re
333       "label:\\([a-zA-Z0-9-_:]*,?\\)*")
334
335
336 (setq org-ref-ref-re
337       "\\(eq\\)?ref:\\([a-zA-Z0-9-_:]*,?\\)*")
338
339
340 (defface org-ref-cite-face
341   `((t (:inherit org-link :foreground ,org-ref-cite-color)))
342   "Color for cite-like links in org-ref.")
343
344
345 (defface org-ref-label-face
346   `((t (:inherit org-link :foreground ,org-ref-label-color)))
347   "Color for ref links in org-ref.")
348
349
350 (defface org-ref-ref-face
351   `((t (:inherit org-link :foreground ,org-ref-ref-color)))
352   "Face for ref links in org-ref.")
353
354
355 (defun org-ref-colorize-links ()
356   "Colorize org-ref links."
357   (hi-lock-mode 1)
358   (highlight-regexp org-ref-cite-re 'org-ref-cite-face)
359   (highlight-regexp org-ref-label-re 'org-ref-label-face)
360   (highlight-regexp org-ref-ref-re 'org-ref-ref-face))
361
362
363 (when org-ref-colorize-links
364   (add-hook 'org-mode-hook 'org-ref-colorize-links))
365
366 ;; * General org-ref utilities
367 (defun org-ref-strip-string (string)
368   "Strip leading and trailing whitespace from the STRING."
369   (replace-regexp-in-string
370    (concat search-whitespace-regexp "$" ) ""
371    (replace-regexp-in-string
372     (concat "^" search-whitespace-regexp ) "" string)))
373
374 (defun org-ref-split-and-strip-string (string)
375   "Split key-string and strip keys in STRING.
376 Assumes the key-string is comma delimited."
377   (mapcar 'org-ref-strip-string (split-string string ",")))
378
379 (defun org-ref-reftex-get-bib-field (field entry &optional format)
380   "Similar to reftex-get-bib-field, but removes enclosing braces and quotes in FIELD in the bibtex ENTRY.
381 Optional argument FORMAT bibtex format."
382   (let ((result))
383     (setq result (reftex-get-bib-field field entry format))
384     (when (and (not (string= result "")) (string= "{" (substring result 0 1)))
385       (setq result (substring result 1 -1)))
386     (when (and (not (string= result "")) (string= "\"" (substring result 0 1)))
387       (setq result (substring result 1 -1)))
388       result))
389
390 (defun org-ref-reftex-format-citation (entry format)
391   "Return a formatted string for the bibtex ENTRY (from bibtex-parse-entry) according to the FORMAT argument.
392 The format is a string with these percent escapes.
393
394 In the format, the following percent escapes will be expanded.
395
396 %l   The BibTeX label of the citation.
397 %a   List of author names, see also `reftex-cite-punctuation'.
398 %2a  Like %a, but abbreviate more than 2 authors like Jones et al.
399 %A   First author name only.
400 %e   Works like %a, but on list of editor names. (%2e and %E work a well)
401
402 It is also possible to access all other BibTeX database fields:
403 %b booktitle     %c chapter        %d edition    %h howpublished
404 %i institution   %j journal        %k key        %m month
405 %n number        %o organization   %p pages      %P first page
406 %r address       %s school         %u publisher  %t title
407 %v volume        %y year
408 %B booktitle, abbreviated          %T title, abbreviated
409 %U url
410 %D doi
411 %S series
412
413 Usually, only %l is needed.  The other stuff is mainly for the echo area
414 display, and for (setq reftex-comment-citations t).
415
416 %< as a special operator kills punctuation and space around it after the
417 string has been formatted.
418
419 A pair of square brackets indicates an optional argument, and RefTeX
420 will prompt for the values of these arguments.
421
422 Beware that all this only works with BibTeX database files.  When
423 citations are made from the \bibitems in an explicit thebibliography
424 environment, only %l is available."
425   ;; Format a citation from the info in the BibTeX ENTRY
426   (unless (stringp format) (setq format "\\cite{%l}"))
427
428   (if (and reftex-comment-citations
429            (string-match "%l" reftex-cite-comment-format))
430       (error "Reftex-cite-comment-format contains invalid %%l"))
431
432   (while (string-match
433           "\\(\\`\\|[^%]\\)\\(\\(%\\([0-9]*\\)\\([a-zA-Z]\\)\\)[.,;: ]*\\)"
434           format)
435     (let ((n (string-to-number (match-string 4 format)))
436           (l (string-to-char (match-string 5 format)))
437           rpl b e)
438       (save-match-data
439         (setq rpl
440               (cond
441                ((= l ?l) (concat
442                           (org-ref-reftex-get-bib-field "&key" entry)
443                           (if reftex-comment-citations
444                               reftex-cite-comment-format
445                             "")))
446                ((= l ?a) (reftex-format-names
447                           (reftex-get-bib-names "author" entry)
448                           (or n 2)))
449                ((= l ?A) (car (reftex-get-bib-names "author" entry)))
450                ((= l ?b) (org-ref-reftex-get-bib-field "booktitle" entry "in: %s"))
451                ((= l ?B) (reftex-abbreviate-title
452                           (org-ref-reftex-get-bib-field "booktitle" entry "in: %s")))
453                ((= l ?c) (org-ref-reftex-get-bib-field "chapter" entry))
454                ((= l ?d) (org-ref-reftex-get-bib-field "edition" entry))
455                ((= l ?D) (org-ref-reftex-get-bib-field "doi" entry))
456                ((= l ?e) (reftex-format-names
457                           (reftex-get-bib-names "editor" entry)
458                           (or n 2)))
459                ((= l ?E) (car (reftex-get-bib-names "editor" entry)))
460                ((= l ?h) (org-ref-reftex-get-bib-field "howpublished" entry))
461                ((= l ?i) (org-ref-reftex-get-bib-field "institution" entry))
462                ((= l ?j) (org-ref-reftex-get-bib-field "journal" entry))
463                ((= l ?k) (org-ref-reftex-get-bib-field "key" entry))
464                ((= l ?m) (org-ref-reftex-get-bib-field "month" entry))
465                ((= l ?n) (org-ref-reftex-get-bib-field "number" entry))
466                ((= l ?o) (org-ref-reftex-get-bib-field "organization" entry))
467                ((= l ?p) (org-ref-reftex-get-bib-field "pages" entry))
468                ((= l ?P) (car (split-string
469                                (org-ref-reftex-get-bib-field "pages" entry)
470                                "[- .]+")))
471                ((= l ?s) (org-ref-reftex-get-bib-field "school" entry))
472                ((= l ?S) (org-ref-reftex-get-bib-field "series" entry))
473                ((= l ?u) (org-ref-reftex-get-bib-field "publisher" entry))
474                ((= l ?U) (org-ref-reftex-get-bib-field "url" entry))
475                ((= l ?r) (org-ref-reftex-get-bib-field "address" entry))
476                ;; strip enclosing brackets from title if they are there
477                ((= l ?t) (org-ref-reftex-get-bib-field "title" entry))
478                ((= l ?T) (reftex-abbreviate-title
479                           (org-ref-reftex-get-bib-field "title" entry)))
480                ((= l ?v) (org-ref-reftex-get-bib-field "volume" entry))
481                ((= l ?y) (org-ref-reftex-get-bib-field "year" entry)))))
482
483       (if (string= rpl "")
484           (setq b (match-beginning 2) e (match-end 2))
485         (setq b (match-beginning 3) e (match-end 3)))
486       (setq format (concat (substring format 0 b) rpl (substring format e)))))
487   (while (string-match "%%" format)
488     (setq format (replace-match "%" t t format)))
489   (while (string-match "[ ,.;:]*%<" format)
490     (setq format (replace-match "" t t format)))
491   ;; also replace carriage returns, tabs, and multiple whitespaces
492   (setq format (replace-regexp-in-string "\n\\|\t\\|\s+" " " format))
493   format)
494
495 (defun org-ref-get-bibtex-entry-citation (key)
496   "Return a string for the bibliography entry corresponding to KEY.
497 Format according to the type in `org-ref-bibliography-entry-format'."
498
499   (let ((org-ref-bibliography-files (org-ref-find-bibliography))
500         (file) (entry) (bibtex-entry) (entry-type) (format))
501
502     (setq file (catch 'result
503                  (loop for file in org-ref-bibliography-files do
504                        (if (org-ref-key-in-file-p key (file-truename file))
505                            (throw 'result file)
506                          (message "%s not found in %s"
507                                   key (file-truename file))))))
508
509     (with-temp-buffer
510       (insert-file-contents file)
511       (bibtex-search-entry key nil 0)
512       (setq bibtex-entry (bibtex-parse-entry))
513       ;; downcase field names so they work in the format-citation code
514       (dolist (cons-cell bibtex-entry)
515         (setf (car cons-cell) (downcase (car cons-cell))))
516       (setq entry-type (downcase (cdr (assoc "=type=" bibtex-entry))))
517       (setq format (cdr (assoc entry-type org-ref-bibliography-entry-format)))
518       (if format
519           (setq entry  (org-ref-reftex-format-citation bibtex-entry format))
520         ;; if no format, we use the bibtex entry itself as a fallback
521         (save-restriction
522           (bibtex-narrow-to-entry)
523           (setq entry (buffer-string)))))
524     entry))
525
526 (defun org-ref-get-bibtex-keys ()
527   "Return a list of unique keys in the buffer."
528   (let ((keys '()))
529     (org-element-map (org-element-parse-buffer) 'link
530       (lambda (link)
531         (let ((plist (nth 1 link)))
532           (when (-contains? org-ref-cite-types (plist-get plist ':type))
533             (dolist
534                 (key
535                  (org-ref-split-and-strip-string (plist-get plist ':path)))
536               (when (not (-contains? keys key))
537                 (setq keys (append keys (list key))))))))
538       ;; set with-affiliated to get keys in captions
539       nil nil nil t)
540     ;; Sort keys alphabetically
541     (setq keys (cl-sort keys 'string-lessp :key 'downcase))
542     keys))
543
544 (defun org-ref-get-bibtex-entry-html (key)
545   "Return an html string for the bibliography entry corresponding to KEY."
546   (let ((output))
547     (setq output (org-ref-get-bibtex-entry-citation key))
548     ;; unescape the &
549     (setq output (replace-regexp-in-string "\\\\&" "&" output))
550     ;; hack to replace {} around text
551     (setq output (replace-regexp-in-string " {\\(.*\\)} " " \\1 " output))
552     ;; get rid of empty parens
553     (setq output (replace-regexp-in-string "()" "" output))
554     ;; get rid of empty link and doi
555     (setq output (replace-regexp-in-string " <a href=\"\">link</a>\\." "" output))
556     (setq output (replace-regexp-in-string " <a href=\"http://dx\\.doi\\.org/\">doi</a>\\." "" output))
557     (format "<li><a id=\"%s\">[%s] %s</a></li>"
558             key key output)))
559
560 (defun org-ref-get-html-bibliography ()
561   "Create an html bibliography when there are keys."
562   (let ((keys (org-ref-get-bibtex-keys)))
563     (when keys
564       (concat "<h1>Bibliography</h1>
565 <ul>"
566               (mapconcat (lambda (x) (org-ref-get-bibtex-entry-html x)) keys "\n")
567               "\n</ul>"))))
568
569 (defun org-ref-get-bibtex-entry-org (key)
570   "Return an org string for the bibliography entry corresponding to KEY."
571   (let ((org-ref-bibliography-files (org-ref-find-bibliography))
572         (file) (entry) (bibtex-entry) (entry-type) (format))
573
574     (setq file (catch 'result
575                  (loop for file in org-ref-bibliography-files do
576                        (if (org-ref-key-in-file-p key (file-truename file))
577                            (throw 'result file)
578                          (message "%s not found in %s" key (file-truename file))))))
579
580     (with-temp-buffer
581       (insert-file-contents file)
582       (bibtex-search-entry key nil 0)
583       (setq entry (bibtex-parse-entry))
584       (format "** %s - %s
585   :PROPERTIES:
586   %s
587   :END:
588 " (org-ref-reftex-get-bib-field "author" entry)
589 (org-ref-reftex-get-bib-field "title" entry)
590 (concat "   :CUSTOM_ID: " (org-ref-reftex-get-bib-field "=key=" entry) "\n"
591         (mapconcat (lambda (element) (format "   :%s: %s"
592                                              (upcase (car element))
593                                              (cdr element)))
594                    entry
595                    "\n"))))))
596
597 (defun org-ref-get-org-bibliography ()
598   "Create an org bibliography when there are keys."
599   (let ((keys (org-ref-get-bibtex-keys)))
600     (when keys
601       (concat "* Bibliography
602 "
603               (mapconcat (lambda (x) (org-ref-get-bibtex-entry-org x)) keys "\n")
604               "\n"))))
605
606 (defun org-ref-get-bibtex-entry-ascii (key)
607   "Return an ascii string for the bibliography entry corresponding to KEY."
608
609   (format "[%s] %s" key (org-ref-get-bibtex-entry-citation key)))
610
611 (defun org-ref-get-ascii-bibliography ()
612   "Create an html bibliography when there are keys."
613   (let ((keys (org-ref-get-bibtex-keys)))
614     (when keys
615       (concat
616 "Bibliography
617 =============
618 "
619               (mapconcat (lambda (x) (org-ref-get-bibtex-entry-ascii x)) keys "\n")
620               "\n"))))
621
622 ;; * Links
623 ;; ** bibliography and bibliographystyle
624 (org-add-link-type "bibliography"
625                    ;; this code is run on clicking. The bibliography
626                    ;; may contain multiple files. this code finds the
627                    ;; one you clicked on and opens it.
628                    (lambda (link-string)
629                        ;; get link-string boundaries we have to go to the
630                        ;; beginning of the line, and then search forward
631                      (let* ((bibfile)
632                             ;; object is the link you clicked on
633                             (object (org-element-context))
634                             (link-string-beginning)
635                             (link-string-end)
636                             (cp (point)))
637                      (save-excursion
638                        (goto-char (org-element-property :begin object))
639                        (search-forward link-string nil nil 1)
640                        (setq link-string-beginning (match-beginning 0))
641                        (setq link-string-end (match-end 0)))
642
643                      ;; Make sure point is in the link-path.
644                      (if (< cp link-string-beginning)
645                          (goto-char link-string-beginning))
646                      ;; We set the reftex-default-bibliography
647                      ;; here. it should be a local variable only in
648                      ;; the current buffer. We need this for using
649                      ;; reftex to do citations.
650                      (set (make-local-variable 'reftex-default-bibliography)
651                           (split-string
652                            (org-element-property :path object) ","))
653
654                      ;; now if we have comma separated bibliographies
655                      ;; we find the one clicked on. we want to
656                      ;; search forward to next comma from point
657                      (save-excursion
658                        (if (search-forward "," link-string-end 1 1)
659                            ;; we found a match
660                            (setq key-end (- (match-end 0) 1))
661                          ;; no comma found so take the point
662                          (setq key-end (point))))
663                      ;; and backward to previous comma from point
664                      (save-excursion
665                        (if (search-backward "," link-string-beginning 1 1)
666                            ;; we found a match
667                            (setq key-beginning (+ (match-beginning 0) 1))
668                          (setq key-beginning (point)))) ; no match found
669                        ;; save the key we clicked on.
670                      (setq bibfile (org-ref-strip-string
671                                     (buffer-substring key-beginning key-end)))
672                      ;; open file on click
673                      (find-file bibfile)))
674
675                    ;; formatting code
676                    (lambda (keyword desc format)
677                      (cond
678                       ((eq format 'org) (org-ref-get-org-bibliography))
679                       ((eq format 'ascii) (org-ref-get-ascii-bibliography))
680                       ((eq format 'html) (org-ref-get-html-bibliography))
681                       ((eq format 'latex)
682                        ;; write out the latex bibliography command
683                        (format "\\bibliography{%s}"
684                                (replace-regexp-in-string
685                                 "\\.bib" ""
686                                 (mapconcat
687                                  'identity
688                                  (mapcar 'expand-file-name
689                                          (split-string keyword ","))
690                                  ",")))))))
691
692 (org-add-link-type "nobibliography"
693                    ;; this code is run on clicking. The bibliography
694                    ;; may contain multiple files. this code finds the
695                    ;; one you clicked on and opens it.
696                    (lambda (link-string)
697                        ;; get link-string boundaries
698                        ;; we have to go to the beginning of the line, and then search forward
699
700                      (let* ((bibfile)
701                             ;; object is the link you clicked on
702                             (object (org-element-context))
703
704                             (link-string-beginning)
705                             (link-string-end))
706
707                      (save-excursion
708                        (goto-char (org-element-property :begin object))
709                        (search-forward link-string nil nil 1)
710                        (setq link-string-beginning (match-beginning 0))
711                        (setq link-string-end (match-end 0)))
712
713                        ;; We set the reftex-default-bibliography
714                        ;; here. it should be a local variable only in
715                        ;; the current buffer. We need this for using
716                        ;; reftex to do citations.
717                        (set (make-local-variable 'reftex-default-bibliography)
718                             (split-string (org-element-property :path object) ","))
719
720                        ;; now if we have comma separated bibliographies
721                        ;; we find the one clicked on. we want to
722                        ;; search forward to next comma from point
723                        (save-excursion
724                          (if (search-forward "," link-string-end 1 1)
725                              (setq key-end (- (match-end 0) 1)) ; we found a match
726                            (setq key-end (point)))) ; no comma found so take the point
727                        ;; and backward to previous comma from point
728                        (save-excursion
729                          (if (search-backward "," link-string-beginning 1 1)
730                              (setq key-beginning (+ (match-beginning 0) 1)) ; we found a match
731                            (setq key-beginning (point)))) ; no match found
732                        ;; save the key we clicked on.
733                        (setq bibfile (org-ref-strip-string (buffer-substring key-beginning key-end)))
734                        (find-file bibfile))) ; open file on click
735
736                      ;; formatting code
737                    (lambda (keyword desc format)
738                      (cond
739                       ((eq format 'org) (org-ref-get-org-bibliography))
740                       ((eq format 'ascii) (org-ref-get-ascii-bibliography))
741                       ((eq format 'html) (org-ref-get-html-bibliography))
742                       ((eq format 'latex)
743                        ;; write out the latex bibliography command
744                        (format "\\nobibliography{%s}"
745                                (replace-regexp-in-string  "\\.bib" "" (mapconcat 'identity
746                                                                                  (mapcar 'expand-file-name
747                                                                                          (split-string keyword ","))
748                                                                                  ",")))))))
749
750 (org-add-link-type "printbibliography"
751                    (lambda (arg) (message "Nothing implemented for clicking here."))
752                    (lambda (keyword desc format)
753                      (cond
754                       ((eq format 'org) (org-ref-get-org-bibliography))
755                       ((eq format 'html) (org-ref-get-html-bibliography))
756                       ((eq format 'latex)
757                        ;; write out the biblatex bibliography command
758                        "\\printbibliography"))))
759
760 (org-add-link-type "bibliographystyle"
761                    (lambda (arg) (message "Nothing implemented for clicking here."))
762                    (lambda (keyword desc format)
763                      (cond
764                       ((eq format 'latex)
765                        ;; write out the latex bibliography command
766                        (format "\\bibliographystyle{%s}" keyword))
767                       ;; Other styles should not have an output for this
768                       (t
769                        ""))))
770
771
772 (defun org-bibliographystyle-complete-link (&optional arg)
773   "Completion function for bibliographystyle link.
774 ARG does nothing."
775   (format "bibliographystyle:%s" (ido-completing-read
776                                   "style: "
777                                   '("unsrt" "plain" "alpha"
778                                     ;; natbib
779                                     ;; https://www.sharelatex.com/learn/Natbib_bibliography_styles
780                                     "dinat" "humannat" "plainnat"
781                                     "abbrnat" "unsrtnat" "rusnat"
782                                     "ksfhnat"))))
783
784
785 (defun org-bibliography-complete-link (&optional arg)
786   "Completion function for bibliography link.
787 ARG does nothing."
788   (format "bibliography:%s" (read-file-name "enter file: " nil nil t)))
789
790
791 (defun org-ref-insert-bibliography-link ()
792   "Insert a bibliography with completion."
793   (interactive)
794   (insert (org-bibliography-complete-link)))
795
796 ;; ** addbibresource
797
798 (org-add-link-type "addbibresource"
799                    ;; this code is run on clicking. The addbibresource
800                    ;; may contain multiple files. this code finds the
801                    ;; one you clicked on and opens it.
802                    (lambda (link-string)
803                        ;; get link-string boundaries
804                        ;; we have to go to the beginning of the line, and then search forward
805
806                      (let* ((bibfile)
807                             ;; object is the link you clicked on
808                             (object (org-element-context))
809
810                             (link-string-beginning)
811                             (link-string-end))
812
813                      (save-excursion
814                        (goto-char (org-element-property :begin object))
815                        (search-forward link-string nil nil 1)
816                        (setq link-string-beginning (match-beginning 0))
817                        (setq link-string-end (match-end 0)))
818
819                        ;; We set the reftex-default-addbibresource
820                        ;; here. it should be a local variable only in
821                        ;; the current buffer. We need this for using
822                        ;; reftex to do citations.
823                        (set (make-local-variable 'reftex-default-addbibresource)
824                             (split-string (org-element-property :path object) ","))
825
826                        ;; now if we have comma separated bibliographies
827                        ;; we find the one clicked on. we want to
828                        ;; search forward to next comma from point
829                        (save-excursion
830                          (if (search-forward "," link-string-end 1 1)
831                              (setq key-end (- (match-end 0) 1)) ; we found a match
832                            (setq key-end (point)))) ; no comma found so take the point
833                        ;; and backward to previous comma from point
834                        (save-excursion
835                          (if (search-backward "," link-string-beginning 1 1)
836                              (setq key-beginning (+ (match-beginning 0) 1)) ; we found a match
837                            (setq key-beginning (point)))) ; no match found
838                        ;; save the key we clicked on.
839                        (setq bibfile (org-ref-strip-string (buffer-substring key-beginning key-end)))
840                        (find-file bibfile))) ; open file on click
841
842                      ;; formatting code
843                    (lambda (keyword desc format)
844                      (cond
845                       ((eq format 'html) (format "")); no output for html
846                       ((eq format 'latex)
847                          ;; write out the latex addbibresource command
848                        (format "\\addbibresource{%s}" keyword)))))
849
850 ;; ** List of figures
851 (defun org-ref-list-of-figures (&optional arg)
852   "Generate buffer with list of figures in them.
853 ARG does nothing."
854   (interactive)
855   (save-excursion (widen)
856   (let* ((c-b (buffer-name))
857          (counter 0)
858          (list-of-figures
859           (org-element-map (org-element-parse-buffer) 'link
860             (lambda (link)
861               "create a link for to the figure"
862               (when
863                   (and (string= (org-element-property :type link) "file")
864                        (string-match-p
865                         "[^.]*\\.\\(png\\|jpg\\|eps\\|pdf\\)$"
866                         (org-element-property :path link)))
867                 (incf counter)
868
869                 (let* ((start (org-element-property :begin link))
870                        (parent (car (cdr (org-element-property :parent link))))
871                        (caption (caaar (plist-get parent :caption)))
872                        (name (plist-get parent :name)))
873                   (if caption
874                       (format
875                        "[[elisp:(progn (switch-to-buffer \"%s\")(widen)(goto-char %s))][figure %s: %s]] %s\n"
876                        c-b start counter (or name "") caption)
877                     (format
878                      "[[elisp:(progn (switch-to-buffer \"%s\")(widen)(goto-char %s))][figure %s: %s]]\n"
879                      c-b start counter (or name "")))))))))
880     (switch-to-buffer "*List of Figures*")
881     (setq buffer-read-only nil)
882     (org-mode)
883     (erase-buffer)
884     (insert (mapconcat 'identity list-of-figures ""))
885     (setq buffer-read-only t)
886     (use-local-map (copy-keymap org-mode-map))
887     (local-set-key "q" #'(lambda () (interactive) (kill-buffer))))))
888
889 (org-add-link-type
890  "list-of-figures"
891  'org-ref-list-of-figures ; on click
892  (lambda (keyword desc format)
893    (cond
894     ((eq format 'latex)
895      (format "\\listoffigures")))))
896
897 ;; ** List of tables
898 (defun org-ref-list-of-tables (&optional arg)
899   "Generate a buffer with a list of tables.
900 ARG does nothing."
901   (interactive)
902   (save-excursion
903   (widen)
904   (let* ((c-b (buffer-name))
905          (counter 0)
906          (list-of-tables
907           (org-element-map (org-element-parse-buffer 'element) 'table
908             (lambda (table)
909               "create a link for to the table"
910               (incf counter)
911               (let ((start (org-element-property :begin table))
912                     (name  (org-element-property :name table))
913                     (caption (caaar (org-element-property :caption table))))
914                 (if caption
915                     (format
916                      "[[elisp:(progn (switch-to-buffer \"%s\")(widen)(goto-char %s))][table %s: %s]] %s\n"
917                      c-b start counter (or name "") caption)
918                   (format
919                    "[[elisp:(progn (switch-to-buffer \"%s\")(widen)(goto-char %s))][table %s: %s]]\n"
920                    c-b start counter (or name ""))))))))
921     (switch-to-buffer "*List of Tables*")
922     (setq buffer-read-only nil)
923     (org-mode)
924     (erase-buffer)
925     (insert (mapconcat 'identity list-of-tables ""))
926     (setq buffer-read-only t)
927     (use-local-map (copy-keymap org-mode-map))
928     (local-set-key "q" #'(lambda () (interactive) (kill-buffer))))))
929
930 (org-add-link-type
931  "list-of-tables"
932  'org-ref-list-of-tables
933  (lambda (keyword desc format)
934    (cond
935     ((eq format 'latex)
936      (format "\\listoftables")))))
937
938
939 ;; ** label link
940 (defun org-ref-count-labels (label)
941   "Counts number of matches for LABEL in the document."
942   (+ (count-matches (format "label:%s\\b[^-:]" label) (point-min) (point-max))
943      ;; for tblname, it is not enough to get word boundary
944      ;; tab-little and tab-little-2 match then.
945      (count-matches (format "^#\\+tblname:\\s-*%s\\b[^-:]" label) (point-min) (point-max))
946      (count-matches (format "\\label{%s}" label) (point-min) (point-max))
947      ;; this is the org-format #+label:
948      (count-matches (format "^#\\+label:\\s-*%s\\b[^-:]" label) (point-min) (point-max))
949      (let ((custom-id-count 0))
950        (org-map-entries
951         (lambda ()
952           (when (string= label (org-entry-get (point) "CUSTOM_ID"))
953             (setq custom-id-count (+ 1 custom-id-count)))))
954        custom-id-count)))
955
956 (org-add-link-type
957  "label"
958  (lambda (label)
959    "on clicking count the number of label tags used in the buffer. A number greater than one means multiple labels!"
960    (let ((count (org-ref-count-labels label)))
961    (message (format "%s occurence%s"
962                     count
963                     (if (or (= count 0)
964                               (> count 1))
965                         "s"
966                       ""))
967                     (org-ref-count-labels label))))
968  (lambda (keyword desc format)
969    (cond
970     ((eq format 'html) (format "(<label>%s</label>)" path))
971     ((eq format 'latex)
972      (format "\\label{%s}" keyword)))))
973
974 (defun org-label-store-link ()
975   "Store a link to a label.  The output will be a ref to that label."
976   ;; First we have to make sure we are on a label link.
977   (let* ((object (org-element-context)))
978     (when (and (equal (org-element-type object) 'link)
979                (equal (org-element-property :type object) "label"))
980       (org-store-link-props
981        :type "ref"
982        :link (concat "ref:" (org-element-property :path object))))
983
984     ;; Store link on table
985     (when (equal (org-element-type object) 'table)
986       (org-store-link-props
987        :type "ref"
988        :link (concat "ref:" (org-element-property :name object))))
989
990     ;; store link on heading with custom_id
991     ;; this is not a ref link, but it is still what you want
992     (when (and (equal (org-element-type object) 'headline)
993                (org-entry-get (point) "CUSTOM_ID"))
994       (org-store-link-props
995        :type "custom_id"
996        :link (format "[[#%s]]" (org-entry-get (point) "CUSTOM_ID"))))
997
998     ;; and to #+label: lines
999
1000     (when (and (equal (org-element-type object) 'paragraph)
1001                (org-element-property :name object))
1002       (org-store-link-props
1003        :type "ref"
1004        :link (concat "ref:" (org-element-property :name object))))))
1005
1006 (add-hook 'org-store-link-functions 'org-label-store-link)
1007
1008 ;; ** ref link
1009 (org-add-link-type
1010  "ref"
1011  (lambda (label)
1012    "on clicking goto the label. Navigate back with C-c &"
1013    (org-mark-ring-push)
1014    ;; next search from beginning of the buffer
1015    ;; it is possible you would not find the label if narrowing is in effect
1016    (widen)
1017    (unless
1018        (or
1019         ;; our label links
1020         (progn
1021           (goto-char (point-min))
1022           (re-search-forward (format "label:%s\\b" label) nil t))
1023
1024         ;; a latex label
1025         (progn
1026           (goto-char (point-min))
1027           (re-search-forward (format "\\label{%s}" label) nil t))
1028
1029         ;; #+label: name  org-definition
1030         (progn
1031           (goto-char (point-min))
1032           (re-search-forward
1033            (format "^#\\+label:\\s-*\\(%s\\)\\b" label) nil t))
1034
1035         ;; org tblname
1036         (progn
1037           (goto-char (point-min))
1038           (re-search-forward
1039            (format "^#\\+tblname:\\s-*\\(%s\\)\\b" label) nil t)))
1040
1041      ;; we did not find anything, so go back to where we came
1042      (org-mark-ring-goto)
1043      (error "%s not found" label))
1044    (org-show-entry)
1045    (message "go back with (org-mark-ring-goto) `C-c &`"))
1046  ;formatting
1047  (lambda (keyword desc format)
1048    (cond
1049     ((eq format 'html) (format "(<ref>%s</ref>)" path))
1050     ((eq format 'latex)
1051      (format "\\ref{%s}" keyword)))))
1052
1053
1054 (defun org-ref-get-org-labels ()
1055  "Return a list of #+LABEL: labels."
1056   (save-excursion
1057     (goto-char (point-min))
1058     (let ((matches '()))
1059       (while (re-search-forward "^#\\+label:\\s-+\\(.*\\)\\b" (point-max) t)
1060         ;; do not do this for tables. We get those in `org-ref-get-tblnames'.
1061         ;; who would have thought you have save match data here? Trust me. When
1062         ;; I wrote this, you did.
1063         (unless (save-match-data  (equal (car (org-element-at-point)) 'table))
1064           (add-to-list 'matches (match-string-no-properties 1) t)))
1065       matches)))
1066
1067
1068 (defun org-ref-get-custom-ids ()
1069  "Return a list of custom_id properties in the buffer."
1070  (let ((results '()) custom_id)
1071    (org-map-entries
1072     (lambda ()
1073       (let ((custom_id (org-entry-get (point) "CUSTOM_ID")))
1074         (when (not (null custom_id))
1075           (setq results (append results (list custom_id)))))))
1076    results))
1077
1078
1079 (defun org-ref-get-latex-labels ()
1080   "Return list of matchin LaTeX defined labels in buffer."
1081   (save-excursion
1082     (goto-char (point-min))
1083     (let ((matches '()))
1084       (while (re-search-forward "\\\\label{\\([a-zA-z0-9:-]*\\)}" (point-max) t)
1085         (add-to-list 'matches (match-string-no-properties 1) t))
1086       matches)))
1087
1088
1089 (defun org-ref-get-tblnames ()
1090   "Return list of table names in the buffer."
1091   (org-element-map (org-element-parse-buffer 'element) 'table
1092     (lambda (table)
1093       (org-element-property :name table))))
1094
1095
1096 (defun org-ref-get-labels ()
1097   "Return a list of labels in the buffer that you can make a ref link to.
1098 This is used to complete ref links and in helm menus."
1099   (save-excursion
1100     (save-restriction
1101       (widen)
1102       (goto-char (point-min))
1103       (let ((matches '()))
1104         ;; these are the org-ref label:stuff  kinds
1105         (while (re-search-forward
1106                 "[^#+]label:\\([a-zA-z0-9:-]*\\)" (point-max) t)
1107           (add-to-list 'matches (match-string-no-properties 1) t))
1108         ;; now add all the other kinds of labels.
1109         (append matches
1110                 ;; #+label:
1111                 (org-ref-get-org-labels)
1112                 ;; \label{}
1113                 (org-ref-get-latex-labels)
1114                 ;; #+tblname: and actually #+label
1115                 (org-ref-get-tblnames)
1116                 ;; CUSTOM_IDs
1117                 (org-ref-get-custom-ids))))))
1118
1119
1120 (defun org-ref-helm-insert-label-link ()
1121   "Insert a label link. helm just shows you what labels already exist.
1122 If you are on a label link, replace it."
1123   (interactive)
1124   (let* ((labels (org-ref-get-labels))
1125          (cb (current-buffer)))
1126     (helm :sources `(((name . "Existing labels")
1127                       (candidates . ,labels)
1128                       ;; default action is to open to the label
1129                       (action . (lambda (label)
1130                                   ;; unfortunately I do not have markers here
1131                                   (org-open-link-from-string
1132                                    (format "ref:%s" label))))
1133                       ;; if you select a label, replace current one
1134                       (action . (lambda (label)
1135                                   (switch-to-buffer ,cb)
1136                                   (cond
1137                                    ;;  no prefix or on a link
1138                                    ((equal helm-current-prefix-arg nil)
1139                                     (let* ((object (org-element-context))
1140                                            (last-char (save-excursion
1141                                                         (goto-char (org-element-property :end object))
1142                                                         (backward-char)
1143                                                         (if (looking-at " ")
1144                                                             " "
1145                                                           ""))))
1146                                       (when (-contains? '("label")
1147                                                         (org-element-property :type object))
1148                                           ;; we are on a link, so replace it.
1149                                         (setf
1150                                            (buffer-substring
1151                                             (org-element-property :begin object)
1152                                             (org-element-property :end object))
1153                                            (concat
1154                                             (replace-regexp-in-string
1155                                              (org-element-property :path object)
1156                                              label
1157                                              (org-element-property :raw-link object))
1158                                             last-char)))))
1159                                    ;; no prefix options defined
1160                                    ))))
1161                      ;; no matching selection creates a new label
1162                      ((name . "Create new label")
1163                       (dummy)
1164                       ;; default action creates a new label, or replaces old one
1165                       (action .  (lambda (label)
1166                                    (switch-to-buffer ,cb)
1167                                    (let* ((object (org-element-context))
1168                                           (last-char (save-excursion
1169                                                        (goto-char (org-element-property :end object))
1170                                                        (backward-char)
1171                                                        (if (looking-at " ")
1172                                                            " "
1173                                                          ""))))
1174                                      (if (-contains? '("label")
1175                                                      (org-element-property :type object))
1176                                          ;; we are on a link, so replace it.
1177                                          (setf
1178                                           (buffer-substring
1179                                            (org-element-property :begin object)
1180                                            (org-element-property :end object))
1181                                           (concat
1182                                            (replace-regexp-in-string
1183                                             (org-element-property :path object)
1184                                             helm-pattern
1185                                             (org-element-property :raw-link object))
1186                                            last-char))
1187                                        ;; new link
1188                                        (insert
1189                                         (concat
1190                                          "label:"
1191                                          (or label
1192                                              helm-pattern))))))))))))
1193
1194
1195 (defun org-ref-complete-link (&optional arg)
1196   "Completion function for ref links.
1197 Optional argument ARG Does nothing."
1198   (let ((label))
1199     (setq label (completing-read "label: " (org-ref-get-labels)))
1200     (format "ref:%s" label)))
1201
1202
1203 (defun org-ref-insert-ref-link ()
1204   "Completion function for a ref link."
1205  (interactive)
1206  (insert (org-ref-complete-link)))
1207
1208
1209 (defun org-ref-helm-insert-ref-link ()
1210   "Helm menu to insert ref links to labels in the document.
1211 If you are on link, replace with newly selected label.
1212 Use C-u to insert a different kind of ref link.
1213 Use C-u C-u to insert a [[#custom-id]] link"
1214   (interactive)
1215   (let* ((labels (org-ref-get-labels))
1216          (bs (buffer-string))
1217          (contexts (with-temp-buffer
1218                      (insert bs)
1219                      (mapcar 'org-ref-get-label-context labels)))
1220          (cb (current-buffer)))
1221
1222     (helm :input (thing-at-point 'word)
1223           :sources `(((name . "Available labels to ref")
1224                       (candidates . ,(loop for label in labels
1225                                            for context in contexts
1226                                            ;; we do some kludgy adding spaces
1227                                            ;; and bars to make it "easier" to
1228                                            ;; see in helm.
1229                                            collect (cons (concat
1230                                                           label "\n"
1231                                                           (mapconcat
1232                                                            (lambda (x)
1233                                                              (concat "   |" x))
1234                                                            (split-string context "\n")
1235                                                            "\n"
1236                                                            ) "\n\n") label)))
1237                       ;; default action to replace or insert ref link.
1238                       (action . (lambda (label)
1239                                   (switch-to-buffer ,cb)
1240
1241                                   (cond
1242                                    ;;  no prefix or on a link
1243                                    ((equal helm-current-prefix-arg nil)
1244                                     (let* ((object (org-element-context))
1245                                            (last-char (save-excursion
1246                                                         (goto-char (org-element-property :end object))
1247                                                         (backward-char)
1248                                                         (if (looking-at " ")
1249                                                             " "
1250                                                           ""))))
1251                                       (if (-contains? '("ref" "eqref" "pageref" "nameref")
1252                                                       (org-element-property :type object))
1253                                           ;; we are on a link, so replace it.
1254                                           (setf
1255                                            (buffer-substring
1256                                             (org-element-property :begin object)
1257                                             (org-element-property :end object))
1258                                            (concat
1259                                             (replace-regexp-in-string
1260                                              (org-element-property :path object)
1261                                              label
1262                                              (org-element-property :raw-link object))
1263                                             last-char))
1264                                         ;; insert a new link
1265                                         (insert
1266                                          (concat
1267                                           "ref:" label))
1268                                         )))
1269                                    ;; one prefix, alternate ref link
1270                                    ((equal helm-current-prefix-arg '(4))
1271                                     (insert
1272                                      (concat
1273                                       (helm :sources '((name . "Ref link types")
1274                                                        (candidates . ("ref" "eqref" "pageref" "nameref"))
1275                                                        (action . (lambda (x) x))))
1276                                       ":" label)))
1277                                    ;; two prefixes, insert section custom-id link
1278                                    ((equal helm-current-prefix-arg '(16))
1279                                     (insert
1280                                      (format "[[#%s]]" label)))
1281                                    ))
1282                               ))))))
1283
1284 ;; *** pageref link
1285 (org-add-link-type
1286  "pageref"
1287  (lambda (label)
1288    "on clicking goto the label. Navigate back with C-c &"
1289    (org-mark-ring-push)
1290    ;; next search from beginning of the buffer
1291    (widen)
1292    (unless
1293        (or
1294         ;; our label links
1295         (progn
1296           (goto-char (point-min))
1297           (re-search-forward (format "label:%s\\b" label) nil t))
1298
1299         ;; a latex label
1300         (progn
1301           (goto-char (point-min))
1302           (re-search-forward (format "\\label{%s}" label) nil t))
1303
1304         ;; #+label: name  org-definition
1305         (progn
1306           (goto-char (point-min))
1307           (re-search-forward
1308            (format "^#\\+label:\\s-*\\(%s\\)\\b" label) nil t))
1309
1310         ;; org tblname
1311         (progn
1312           (goto-char (point-min))
1313           (re-search-forward
1314            (format "^#\\+tblname:\\s-*\\(%s\\)\\b" label) nil t)))
1315      ;; we did not find anything, so go back to where we came
1316      (org-mark-ring-goto)
1317      (error "%s not found" label))
1318    (message "go back with (org-mark-ring-goto) `C-c &`"))
1319  ;formatting
1320  (lambda (keyword desc format)
1321    (cond
1322     ((eq format 'html) (format "(<pageref>%s</pageref>)" path))
1323     ((eq format 'latex)
1324      (format "\\pageref{%s}" keyword)))))
1325
1326
1327 (defun org-pageref-complete-link (&optional arg)
1328   "Completion function for ref links.
1329 Optional argument ARG Does nothing."
1330   (let ((label))
1331     (setq label (completing-read "label: " (org-ref-get-labels)))
1332     (format "ref:%s" label)))
1333
1334
1335 (defun org-pageref-insert-ref-link ()
1336   "Insert a pageref link with completion."
1337  (interactive)
1338  (insert (org-pageref-complete-link)))
1339
1340
1341 ;; *** nameref link
1342 (org-add-link-type
1343  "nameref"
1344  (lambda (label)
1345    "on clicking goto the label. Navigate back with C-c &"
1346    (org-mark-ring-push)
1347    ;; next search from beginning of the buffer
1348    (widen)
1349    (unless
1350        (or
1351         ;; a latex label
1352         (progn
1353           (goto-char (point-min))
1354           (re-search-forward (format "\\label{%s}" label) nil t))
1355         )
1356      ;; we did not find anything, so go back to where we came
1357      (org-mark-ring-goto)
1358      (error "%s not found" label))
1359    (message "go back with (org-mark-ring-goto) `C-c &`"))
1360  ;formatting
1361  (lambda (keyword desc format)
1362    (cond
1363     ((eq format 'html) (format "(<nameref>%s</nameref>)" path))
1364     ((eq format 'latex)
1365      (format "\\nameref{%s}" keyword)))))
1366
1367 ;; *** eqref link
1368
1369 (org-add-link-type
1370  "eqref"
1371  (lambda (label)
1372    "on clicking goto the label. Navigate back with C-c &"
1373    (org-mark-ring-push)
1374    ;; next search from beginning of the buffer
1375    (widen)
1376    (goto-char (point-min))
1377    (unless
1378        (or
1379         ;; search forward for the first match
1380         ;; our label links
1381         (re-search-forward (format "label:%s" label) nil t)
1382         ;; a latex label
1383         (re-search-forward (format "\\label{%s}" label) nil t)
1384         ;; #+label: name  org-definition
1385         (re-search-forward (format "^#\\+label:\\s-*\\(%s\\)\\b" label) nil t))
1386      (org-mark-ring-goto)
1387      (error "%s not found" label))
1388    (message "go back with (org-mark-ring-goto) `C-c &`"))
1389  ;formatting
1390  (lambda (keyword desc format)
1391    (cond
1392     ((eq format 'html) (format "(<eqref>%s</eqref>)" path))
1393     ((eq format 'latex)
1394      (format "\\eqref{%s}" keyword)))))
1395
1396 ;; ** cite link
1397
1398 (defun org-ref-get-bibtex-key-under-cursor ()
1399   "Return key under the bibtex cursor.
1400 We search forward from
1401 point to get a comma, or the end of the link, and then backwards
1402 to get a comma, or the beginning of the link.  that delimits the
1403 keyword we clicked on.  We also strip the text properties."
1404   (let* ((object (org-element-context))
1405          (link-string (org-element-property :path object)))
1406     ;; you may click on the part before the citations. here we make
1407     ;; sure to move to the beginning so you get the first citation.
1408     (let ((cp (point)))
1409       (goto-char (org-element-property :begin object))
1410       (search-forward link-string (org-element-property :end object))
1411       (goto-char (match-beginning 0))
1412       ;; check if we clicked before the path and move as needed.
1413       (unless (< cp (point))
1414         (goto-char cp)))
1415
1416     (if (not (org-element-property :contents-begin object))
1417         ;; this means no description in the link
1418         (progn
1419           ;; we need the link path start and end
1420           (save-excursion
1421             (goto-char (org-element-property :begin object))
1422             (search-forward link-string nil nil 1)
1423             (setq link-string-beginning (match-beginning 0))
1424             (setq link-string-end (match-end 0)))
1425
1426           ;; The key is the text between commas, or the link boundaries
1427           (save-excursion
1428             (if (search-forward "," link-string-end t 1)
1429                 (setq key-end (- (match-end 0) 1)) ; we found a match
1430               (setq key-end link-string-end))) ; no comma found so take the end
1431           ;; and backward to previous comma from point which defines the start character
1432           (save-excursion
1433             (if (search-backward "," link-string-beginning 1 1)
1434                 (setq key-beginning (+ (match-beginning 0) 1)) ; we found a match
1435               (setq key-beginning link-string-beginning))) ; no match found
1436           ;; save the key we clicked on.
1437           (setq bibtex-key
1438                 (org-ref-strip-string
1439                  (buffer-substring key-beginning key-end)))
1440           (set-text-properties 0 (length bibtex-key) nil bibtex-key)
1441           bibtex-key)
1442       ;; link with description. assume only one key
1443       link-string)))
1444
1445 (defun org-ref-find-bibliography ()
1446   "Find the bibliography in the buffer.
1447 This function sets and returns cite-bibliography-files, which is a list of files
1448 either from bibliography:f1.bib,f2.bib
1449 \bibliography{f1,f2}
1450 internal bibliographies
1451
1452 falling back to what the user has set in `org-ref-default-bibliography'"
1453   (catch 'result
1454     (save-excursion
1455       (goto-char (point-min))
1456       ;;  look for a bibliography link
1457       (when (re-search-forward "\\<bibliography:\\([^\]\|\n]+\\)" nil t)
1458         (setq org-ref-bibliography-files
1459               (mapcar 'org-ref-strip-string (split-string (match-string 1) ",")))
1460         (throw 'result org-ref-bibliography-files))
1461
1462
1463       ;; we did not find a bibliography link. now look for \bibliography
1464       (goto-char (point-min))
1465       (when (re-search-forward "\\\\bibliography{\\([^}]+\\)}" nil t)
1466         ;; split, and add .bib to each file
1467         (setq org-ref-bibliography-files
1468               (mapcar (lambda (x) (concat x ".bib"))
1469                       (mapcar 'org-ref-strip-string
1470                               (split-string (match-string 1) ","))))
1471         (throw 'result org-ref-bibliography-files))
1472
1473       ;; no bibliography found. maybe we need a biblatex addbibresource
1474       (goto-char (point-min))
1475       ;;  look for a bibliography link
1476       (when (re-search-forward "addbibresource:\\([^\]\|\n]+\\)" nil t)
1477         (setq org-ref-bibliography-files
1478               (mapcar 'org-ref-strip-string (split-string (match-string 1) ",")))
1479         (throw 'result org-ref-bibliography-files))
1480
1481       ;; we did not find anything. use defaults
1482       (setq org-ref-bibliography-files org-ref-default-bibliography)))
1483
1484     ;; set reftex-default-bibliography so we can search
1485     (set (make-local-variable 'reftex-default-bibliography) org-ref-bibliography-files)
1486     org-ref-bibliography-files)
1487
1488 (defun org-ref-key-in-file-p (key filename)
1489   "Determine if the KEY is in the FILENAME."
1490   (save-current-buffer
1491     (let ((bibtex-files (list filename)))
1492       ;; This is something I am trying because when the bibtex file is open, and
1493       ;; you have added to it, the only way I find to get the update to update
1494       ;; is to close it and reopen it. or to save it and revert it.
1495       (when (get-file-buffer filename)
1496         (set-buffer (get-file-buffer filename))
1497         (save-buffer)
1498         (revert-buffer t t))
1499       (bibtex-search-entry key t))))
1500
1501 (defun org-ref-get-bibtex-key-and-file (&optional key)
1502   "Return the bibtex KEY and file that it is in.  If no key is provided, get one under point."
1503  (let ((org-ref-bibliography-files (org-ref-find-bibliography))
1504        (file))
1505    (unless key
1506      (setq key (org-ref-get-bibtex-key-under-cursor)))
1507    (setq file     (catch 'result
1508                     (loop for file in org-ref-bibliography-files do
1509                           (if (org-ref-key-in-file-p key (file-truename file))
1510                               (throw 'result file)))))
1511    (cons key file)))
1512
1513 ;; *** key at point functions
1514
1515 (defun org-ref-open-pdf-at-point ()
1516   "Open the pdf for bibtex key under point if it exists."
1517   (interactive)
1518   (let* ((results (org-ref-get-bibtex-key-and-file))
1519          (key (car results))
1520          (pdf-file (format (concat org-ref-pdf-directory "%s.pdf") key)))
1521     (if (file-exists-p pdf-file)
1522         (org-open-file pdf-file)
1523 (message "no pdf found for %s" key))))
1524
1525
1526 (defun org-ref-open-url-at-point ()
1527   "Open the url for bibtex key under point."
1528   (interactive)
1529   (let* ((results (org-ref-get-bibtex-key-and-file))
1530          (key (car results))
1531          (bibfile (cdr results)))
1532     (save-excursion
1533       (with-temp-buffer
1534         (insert-file-contents bibfile)
1535         (bibtex-search-entry key)
1536         ;; I like this better than bibtex-url which does not always find
1537         ;; the urls
1538         (catch 'done
1539           (let ((url (bibtex-autokey-get-field "url")))
1540             (when  url
1541               (browse-url (s-trim url))
1542               (throw 'done nil)))
1543
1544           (let ((doi (bibtex-autokey-get-field "doi")))
1545             (when doi
1546               (if (string-match "^http" doi)
1547                   (browse-url doi)
1548                 (browse-url (format "http://dx.doi.org/%s" (s-trim doi))))
1549               (throw 'done nil))))))))
1550
1551
1552 (defun org-ref-open-notes-at-point ()
1553   "Open the notes for bibtex key under point."
1554   (interactive)
1555   (let* ((results (org-ref-get-bibtex-key-and-file))
1556          (key (car results))
1557          (bibfile (cdr results)))
1558     (save-excursion
1559       (with-temp-buffer
1560         (insert-file-contents bibfile)
1561         (bibtex-search-entry key)
1562         (org-ref-open-bibtex-notes)))))
1563
1564
1565 (defun org-ref-citation-at-point ()
1566   "Give message of current citation at point."
1567   (interactive)
1568   (let* ((cb (current-buffer))
1569         (results (org-ref-get-bibtex-key-and-file))
1570         (key (car results))
1571         (bibfile (cdr results)))
1572     (message "%s" (progn
1573                     (with-temp-buffer
1574                       (insert-file-contents bibfile)
1575                       (bibtex-search-entry key)
1576                       (org-ref-bib-citation))))))
1577
1578
1579 (defun org-ref-open-citation-at-point ()
1580   "Open bibtex file to key at point."
1581   (interactive)
1582   (let* ((cb (current-buffer))
1583         (results (org-ref-get-bibtex-key-and-file))
1584         (key (car results))
1585         (bibfile (cdr results)))
1586     (find-file bibfile)
1587     (bibtex-search-entry key)))
1588
1589 ;; *** cite menu
1590
1591 (defvar org-ref-cite-menu-funcs '()
1592  "Functions to run on cite click menu.
1593 Each entry is a list of (key menu-name function).
1594 The function must take no arguments and work on the key at point.  Do not modify this variable, it is set to empty in the menu click function, and functions are conditionally added to it.")
1595
1596
1597 (defvar org-ref-user-cite-menu-funcs
1598   '(("C" "rossref" org-ref-crossref-at-point)
1599     ("y" "Copy entry to file" org-ref-copy-entry-at-point-to-file)
1600     ("s" "Copy summary" org-ref-copy-entry-as-summary))
1601   "User-defined functions to run on bibtex key at point.")
1602
1603
1604 (defun org-ref-copy-entry-as-summary ()
1605   "Copy the bibtex entry for the citation at point as a summary."
1606   (interactive)
1607     (save-window-excursion
1608       (org-ref-open-citation-at-point)
1609       (kill-new (org-ref-bib-citation))))
1610
1611
1612 (defun org-ref-copy-entry-at-point-to-file ()
1613   "Copy the bibtex entry for the citation at point to NEW-FILE.
1614 Prompt for NEW-FILE includes bib files in `org-ref-default-bibliography', and bib files in current working directory.  You can also specify a new file."
1615   (interactive)
1616   (let ((new-file (ido-completing-read
1617                    "Copy to bibfile: "
1618                    (append org-ref-default-bibliography
1619                            (f-entries "." (lambda (f) (f-ext? f "bib"))))))
1620         (key (org-ref-get-bibtex-key-under-cursor)))
1621     (save-window-excursion
1622       (org-ref-open-citation-at-point)
1623       (bibtex-copy-entry-as-kill))
1624
1625     (let ((bibtex-files (list (file-truename new-file))))
1626       (if (assoc key (bibtex-global-key-alist))
1627           (message "That key already exists in %s" new-file)
1628         ;; add to file
1629         (save-window-excursion
1630           (find-file new-file)
1631           (goto-char (point-max))
1632           ;; make sure we are at the beginning of a line.
1633           (unless (looking-at "^") (insert "\n\n"))
1634           (bibtex-yank)
1635           (save-buffer))))))
1636
1637
1638 (defun org-ref-get-doi-at-point ()
1639   "Get doi for key at point."
1640   (let* ((results (org-ref-get-bibtex-key-and-file))
1641          (key (car results))
1642          (bibfile (cdr results))
1643          doi)
1644     (save-excursion
1645       (with-temp-buffer
1646         (insert-file-contents bibfile)
1647         (bibtex-search-entry key)
1648         (setq doi (bibtex-autokey-get-field "doi"))
1649         ;; in case doi is a url, remove the url part.
1650         (replace-regexp-in-string "^http://dx.doi.org/" "" doi)))))
1651
1652
1653 ;; **** functions that operate on key at point for click menu
1654 (defun org-ref-wos-at-point ()
1655   "Open the doi in wos for bibtex key under point."
1656   (interactive)
1657   (doi-utils-wos (org-ref-get-doi-at-point)))
1658
1659
1660 (defun org-ref-wos-citing-at-point ()
1661   "Open the doi in wos citing articles for bibtex key under point."
1662   (interactive)
1663   (doi-utils-wos-citing (org-ref-get-doi-at-point)))
1664
1665
1666 (defun org-ref-wos-related-at-point ()
1667   "Open the doi in wos related articles for bibtex key under point."
1668   (interactive)
1669   (doi-utils-wos-related (org-ref-get-doi-at-point)))
1670
1671
1672 (defun org-ref-google-scholar-at-point ()
1673   "Open the doi in google scholar for bibtex key under point."
1674   (interactive)
1675   (doi-utils-google-scholar (org-ref-get-doi-at-point)))
1676
1677
1678 (defun org-ref-pubmed-at-point ()
1679   "Open the doi in pubmed for bibtex key under point."
1680   (interactive)
1681   (doi-utils-pubmed (org-ref-get-doi-at-point)))
1682
1683
1684 (defun org-ref-crossref-at-point ()
1685   "Open the doi in crossref for bibtex key under point."
1686   (interactive)
1687   (doi-utils-crossref (org-ref-get-doi-at-point)))
1688
1689 ;; *** Minibuffer menu
1690
1691 (defun org-ref-cite-onclick-minibuffer-menu (&optional link-string)
1692   "Action when a cite link is clicked on.
1693 Provides a menu of context sensitive actions.  If the bibtex entry
1694 has a pdf, you get an option to open it.  If there is a doi, you
1695 get a lot of options.  LINK-STRING is used by the link function."
1696   (interactive)
1697   (let* ((results (org-ref-get-bibtex-key-and-file))
1698          (key (car results))
1699          (pdf-file (format (concat org-ref-pdf-directory "%s.pdf") key))
1700          (bibfile (cdr results))
1701          (url (save-excursion
1702                 (with-temp-buffer
1703                   (insert-file-contents bibfile)
1704                   (bibtex-search-entry key)
1705                   (bibtex-autokey-get-field "url"))))
1706          (doi (save-excursion
1707                 (with-temp-buffer
1708                   (insert-file-contents bibfile)
1709                   (bibtex-search-entry key)
1710                   ;; I like this better than bibtex-url which does not always find
1711                   ;; the urls
1712                   (bibtex-autokey-get-field "doi")))))
1713
1714     (when (string= "" doi) (setq doi nil))
1715     (when (string= "" url) (setq url nil))
1716     (setq org-ref-cite-menu-funcs '())
1717
1718     ;; open action
1719     (when
1720         bibfile
1721       (add-to-list
1722        'org-ref-cite-menu-funcs
1723        '("o" "pen" org-ref-open-citation-at-point)))
1724
1725     ;; pdf
1726     (when (file-exists-p pdf-file)
1727       (add-to-list
1728        'org-ref-cite-menu-funcs
1729        `("p" "df" ,org-ref-open-pdf-function) t))
1730
1731     ;; notes
1732     (add-to-list
1733      'org-ref-cite-menu-funcs
1734      '("n" "otes" org-ref-open-notes-at-point) t)
1735
1736     ;; url
1737     (when (or url doi)
1738       (add-to-list
1739        'org-ref-cite-menu-funcs
1740        '("u" "rl" org-ref-open-url-at-point) t))
1741
1742     ;; doi funcs
1743     (when doi
1744       (add-to-list
1745        'org-ref-cite-menu-funcs
1746        '("w" "os" org-ref-wos-at-point) t)
1747
1748       (add-to-list
1749        'org-ref-cite-menu-funcs
1750        '("c" "iting" org-ref-wos-citing-at-point) t)
1751
1752       (add-to-list
1753        'org-ref-cite-menu-funcs
1754        '("r" "elated" org-ref-wos-related-at-point) t)
1755
1756       (add-to-list
1757        'org-ref-cite-menu-funcs
1758        '("g" "oogle scholar" org-ref-google-scholar-at-point) t)
1759
1760       (add-to-list
1761        'org-ref-cite-menu-funcs
1762        '("P" "ubmed" org-ref-pubmed-at-point) t))
1763
1764     ;; add user functions
1765     (dolist (tup org-ref-user-cite-menu-funcs)
1766       (add-to-list
1767        'org-ref-cite-menu-funcs
1768        tup t))
1769
1770     ;; finally quit
1771     (add-to-list
1772      'org-ref-cite-menu-funcs
1773      '("q" "uit" (lambda ())) t)
1774
1775     ;; now we make a menu
1776     ;; construct menu string as a message
1777     (message
1778      (concat
1779       (let* ((results (org-ref-get-bibtex-key-and-file))
1780              (key (car results))
1781              (bibfile (cdr results)))
1782         (save-excursion
1783           (with-temp-buffer
1784             (insert-file-contents bibfile)
1785             (bibtex-search-entry key)
1786             (org-ref-bib-citation))))
1787       "\n"
1788       (mapconcat
1789        (lambda (tup)
1790          (concat "[" (elt tup 0) "]"
1791                  (elt tup 1) " "))
1792        org-ref-cite-menu-funcs "")))
1793     ;; get the input
1794     (let* ((input (read-char-exclusive))
1795            (choice (assoc
1796                     (char-to-string input) org-ref-cite-menu-funcs)))
1797       ;; now run the function (2nd element in choice)
1798       (when choice
1799         (funcall
1800          (elt
1801           choice
1802           2))))))
1803
1804 ;; *** Generation of the cite links
1805 (defmacro org-ref-make-completion-function (type)
1806   "Macro to make a link completion function for a link of TYPE."
1807   `(defun ,(intern (format "org-%s-complete-link" type)) (&optional arg)
1808      (interactive)
1809      (format "%s:%s"
1810              ,type
1811              (completing-read
1812               "bibtex key: "
1813               (let ((bibtex-files (org-ref-find-bibliography)))
1814                 (bibtex-global-key-alist))))))
1815
1816 (defmacro org-ref-make-format-function (type)
1817   "Macro to make a format function for a link of TYPE."
1818   `(defun ,(intern (format "org-ref-format-%s" type)) (keyword desc format)
1819      (cond
1820       ((eq format 'org)
1821        (mapconcat
1822         (lambda (key)
1823           (format "[[#%s][%s]]" key key))
1824         (org-ref-split-and-strip-string keyword) ","))
1825
1826       ((eq format 'ascii)
1827        (concat "["
1828                (mapconcat
1829                 (lambda (key)
1830                   (format "%s" key))
1831                 (org-ref-split-and-strip-string keyword) ",") "]"))
1832
1833       ((eq format 'html)
1834        (mapconcat
1835         (lambda (key)
1836           (format "<a href=\"#%s\">%s</a>" key key))
1837         (org-ref-split-and-strip-string keyword) ","))
1838
1839       ((eq format 'latex)
1840        (if (string= (substring type -1) "s")
1841            ;; biblatex format for multicite commands, which all end in s. These are formated as \cites{key1}{key2}...
1842            (concat "\\" ,type (mapconcat (lambda (key) (format "{%s}"  key))
1843                                          (org-ref-split-and-strip-string keyword) ""))
1844          ;; bibtex format
1845        (concat "\\" ,type (when desc (org-ref-format-citation-description desc)) "{"
1846                (mapconcat (lambda (key) key) (org-ref-split-and-strip-string keyword) ",")
1847                "}")))
1848       ;; for markdown we generate pandoc citations
1849       ((eq format 'md)
1850        (cond
1851         (desc  ;; pre and or post text
1852          (let* ((text (split-string desc "::"))
1853                 (pre (car text))
1854                 (post (cadr text)))
1855            (concat
1856             (format "[@%s," keyword)
1857             (when pre (format " %s" pre))
1858             (when post (format ", %s" post))
1859             "]")))
1860         (t
1861          (format "[%s]"
1862                  (mapconcat
1863                   (lambda (key) (concat "@" key))
1864                   (org-ref-split-and-strip-string keyword)
1865                   "; "))))))))
1866
1867 (defun org-ref-format-citation-description (desc)
1868   "Return formatted citation description.
1869 If the cite link has a DESC (description), it is optional text
1870 for the citation command.  You can specify pre and post text by
1871 separating these with ::, for example [[cite:key][pre text::post
1872 text]]."
1873   (cond
1874    ((string-match "::" desc)
1875     (format "[%s][%s]" (car (setq results (split-string desc "::"))) (cadr results)))
1876    (t (format "[%s]" desc))))
1877
1878 (defun org-ref-define-citation-link (type &optional key)
1879   "Add a citation link of TYPE for org-ref.
1880 With optional KEY, set the reftex binding. For example:
1881 \(org-ref-define-citation-link \"citez\" ?z) will create a new
1882 citez link, with reftex key of z, and the completion function."
1883   (interactive "sCitation Type: \ncKey: ")
1884
1885   ;; create the formatting function
1886   (eval `(org-ref-make-format-function ,type))
1887
1888   (eval-expression
1889    `(org-add-link-type
1890      ,type
1891      org-ref-cite-onclick-function
1892      (quote ,(intern (format "org-ref-format-%s" type)))))
1893
1894   ;; create the completion function
1895   (eval `(org-ref-make-completion-function ,type))
1896
1897   ;; store new type so it works with adding citations, which checks
1898   ;; for existence in this list
1899   (add-to-list 'org-ref-cite-types type)
1900
1901   ;; and finally if a key is specified, we modify the reftex menu
1902   (when key
1903     (setf (nth 2 (assoc 'org reftex-cite-format-builtin))
1904           (append (nth 2 (assoc 'org reftex-cite-format-builtin))
1905                   `((,key  . ,(concat type ":%l")))))))
1906
1907 ;; create all the link types and their completion functions
1908 (mapcar 'org-ref-define-citation-link org-ref-cite-types)
1909
1910 (defun org-ref-insert-cite-link (alternative-cite)
1911   "Insert a default citation link using reftex.
1912 If you are on a link, it appends to the end of the link,
1913 otherwise, a new link is inserted.  Use a prefix
1914 arg (ALTERNATIVE-CITE) to get a menu of citation types."
1915   (interactive "P")
1916   (org-ref-find-bibliography)
1917   (let* ((object (org-element-context))
1918          (link-string-beginning (org-element-property :begin object))
1919          (link-string-end (org-element-property :end object))
1920          (path (org-element-property :path object)))
1921
1922     (if (not alternative-cite)
1923
1924         (cond
1925          ;; case where we are in a link
1926          ((and (equal (org-element-type object) 'link)
1927                (-contains? org-ref-cite-types (org-element-property :type object)))
1928           (goto-char link-string-end)
1929           ;; sometimes there are spaces at the end of the link
1930           ;; this code moves point pack until no spaces are there
1931           (while (looking-back " ") (backward-char))
1932           (insert (concat "," (mapconcat 'identity (reftex-citation t ?a) ","))))
1933
1934          ;; We are next to a link, and we want to append
1935          ((save-excursion
1936             (backward-char)
1937             (and (equal (org-element-type (org-element-context)) 'link)
1938                  (-contains? org-ref-cite-types (org-element-property :type (org-element-context)))))
1939           (while (looking-back " ") (backward-char))
1940           (insert (concat "," (mapconcat 'identity (reftex-citation t ?a) ","))))
1941
1942          ;; insert fresh link
1943          (t
1944           (insert
1945            (concat org-ref-default-citation-link
1946                    ":"
1947                    (mapconcat 'identity (reftex-citation t) ",")))))
1948
1949       ;; you pressed a C-u so we run this code
1950       (reftex-citation))))
1951
1952 (defun org-ref-insert-cite-with-completion (type)
1953   "Insert a cite link of TYPE with completion."
1954   (interactive (list (ido-completing-read "Type: " org-ref-cite-types)))
1955   (insert (funcall (intern (format "org-%s-complete-link" type)))))
1956
1957 (defun org-ref-store-bibtex-entry-link ()
1958   "Save a citation link to the current bibtex entry.  Save in the default link type."
1959   (interactive)
1960   (let ((link (concat org-ref-default-citation-link
1961                  ":"
1962                  (save-excursion
1963                    (bibtex-beginning-of-entry)
1964                    (reftex-get-bib-field "=key=" (bibtex-parse-entry))))))
1965     (message "saved %s" link)
1966     (push (list link) org-stored-links)
1967     (car org-stored-links)))
1968
1969 ;; ** Index link
1970 (org-add-link-type
1971  "index"
1972  (lambda (path)
1973    (occur path))
1974
1975  (lambda (path desc format)
1976    (cond
1977     ((eq format 'latex)
1978       (format "\\index{%s}" path)))))
1979
1980 ;; this will generate a temporary index of entries in the file.
1981 (org-add-link-type
1982  "printindex"
1983  (lambda (path)
1984    (let ((*index-links* '())
1985          (*initial-letters* '()))
1986
1987      ;; get links
1988      (org-element-map (org-element-parse-buffer) 'link
1989        (lambda (link)
1990          (let ((type (nth 0 link))
1991                (plist (nth 1 link)))
1992
1993            (when (equal (plist-get plist ':type) "index")
1994              (add-to-list
1995               '*index-links*
1996               (cons (plist-get plist :path)
1997                     (format
1998                      "[[elisp:(progn (switch-to-buffer \"%s\") (goto-char %s))][%s]]"
1999 (current-buffer)
2000                      (plist-get plist :begin)  ;; position of link
2001                      ;; grab a description
2002                      (save-excursion
2003                        (goto-char (plist-get plist :begin))
2004                        (if (thing-at-point 'sentence)
2005                            ;; get a sentence
2006                            (replace-regexp-in-string
2007                             "\n" "" (thing-at-point 'sentence))
2008                          ;; or call it a link
2009                          "link")))))))))
2010
2011      ;; sort the links
2012      (setq *index-links*  (cl-sort *index-links* 'string-lessp :key 'car))
2013
2014      ;; now first letters
2015      (dolist (link *index-links*)
2016        (add-to-list '*initial-letters* (substring (car link) 0 1) t))
2017
2018      ;; now create the index
2019      (switch-to-buffer (get-buffer-create "*index*"))
2020      (org-mode)
2021      (erase-buffer)
2022      (insert "#+TITLE: Index\n\n")
2023      (dolist (letter *initial-letters*)
2024        (insert (format "* %s\n" (upcase letter)))
2025        ;; now process the links
2026        (while (and
2027                *index-links*
2028                (string= letter (substring (car (car *index-links*)) 0 1)))
2029          (let ((link (pop *index-links*)))
2030            (insert (format "%s %s\n\n" (car link) (cdr link))))))
2031      (switch-to-buffer "*index*")))
2032  ;; formatting
2033  (lambda (path desc format)
2034    (cond
2035     ((eq format 'latex)
2036       (format "\\printindex")))))
2037
2038 ;; ** Glossary link
2039 (org-add-link-type
2040  "newglossaryentry"
2041  nil ;; no follow action
2042  (lambda (path desc format)
2043    (cond
2044     ((eq format 'latex)
2045      (format "\\newglossaryentry{%s}{%s}" path desc)))))
2046
2047
2048 ;; link to entry
2049 (org-add-link-type
2050  "gls"
2051   nil ;; no follow action
2052  (lambda (path desc format)
2053    (cond
2054     ((eq format 'latex)
2055      (format "\\gls{%s}" path)))))
2056
2057 ;; plural
2058 (org-add-link-type
2059  "glspl"
2060   nil ;; no follow action
2061  (lambda (path desc format)
2062    (cond
2063     ((eq format 'latex)
2064      (format "\\glspl{%s}" path)))))
2065
2066 ;; capitalized link
2067 (org-add-link-type
2068  "Gls"
2069   nil ;; no follow action
2070  (lambda (path desc format)
2071    (cond
2072     ((eq format 'latex)
2073      (format "\\Gls{%s}" path)))))
2074
2075 ;; capitalized link
2076 (org-add-link-type
2077  "Glspl"
2078   nil ;; no follow action
2079  (lambda (path desc format)
2080    (cond
2081     ((eq format 'latex)
2082      (format "\\Glspl{%s}" path)))))
2083
2084 ;; * Utilities
2085 ;; ** create text citations from a bibtex entry
2086 (defun org-ref-bib-citation ()
2087   "From a bibtex entry, create and return a simple citation string.
2088 This assumes you are in an article."
2089
2090   (bibtex-beginning-of-entry)
2091   (let* ((cb (current-buffer))
2092          (bibtex-expand-strings t)
2093          (entry (loop for (key . value) in (bibtex-parse-entry t)
2094                       collect (cons (downcase key) value)))
2095          (title (replace-regexp-in-string "\n\\|\t\\|\s+" " " (reftex-get-bib-field "title" entry)))
2096          (year  (reftex-get-bib-field "year" entry))
2097          (author (replace-regexp-in-string "\n\\|\t\\|\s+" " " (reftex-get-bib-field "author" entry)))
2098          (key (reftex-get-bib-field "=key=" entry))
2099          (journal (reftex-get-bib-field "journal" entry))
2100          (volume (reftex-get-bib-field "volume" entry))
2101          (pages (reftex-get-bib-field "pages" entry))
2102          (doi (reftex-get-bib-field "doi" entry))
2103          (url (reftex-get-bib-field "url" entry))
2104          )
2105     ;;authors, "title", Journal, vol(iss):pages (year).
2106     (format "%s, \"%s\", %s, %s:%s (%s)"
2107             author title journal  volume pages year)))
2108
2109 (defun org-ref-bib-html-citation ()
2110   "From a bibtex entry, create and return a simple citation with html links."
2111   (bibtex-beginning-of-entry)
2112   (let* ((cb (current-buffer))
2113          (bibtex-expand-strings t)
2114          (entry (loop for (key . value) in (bibtex-parse-entry t)
2115                       collect (cons (downcase key) value)))
2116          (title (replace-regexp-in-string "\n\\|\t\\|\s+" " " (reftex-get-bib-field "title" entry)))
2117          (year  (reftex-get-bib-field "year" entry))
2118          (author (replace-regexp-in-string "\n\\|\t\\|\s+" " " (reftex-get-bib-field "author" entry)))
2119          (key (reftex-get-bib-field "=key=" entry))
2120          (journal (reftex-get-bib-field "journal" entry))
2121          (volume (reftex-get-bib-field "volume" entry))
2122          (pages (reftex-get-bib-field "pages" entry))
2123          (doi (reftex-get-bib-field "doi" entry))
2124          (url (reftex-get-bib-field "url" entry)))
2125     ;;authors, "title", Journal, vol(iss):pages (year).
2126     (concat (format "%s, \"%s\", %s, %s:%s (%s)."
2127                     author title journal  volume pages year)
2128             (when url (format " <a href=\"%s\">link</a>" url))
2129             (when doi
2130               (format " <a href=\"http://dx.doi.org/%s\">doi</a>" doi)))))
2131
2132 ;; ** Open pdf in bibtex entry
2133 (defun org-ref-open-bibtex-pdf ()
2134   "Open pdf for a bibtex entry, if it exists.
2135 assumes point is in
2136 the entry of interest in the bibfile.  but does not check that."
2137   (interactive)
2138   (save-excursion
2139     (bibtex-beginning-of-entry)
2140     (let* ((bibtex-expand-strings t)
2141            (entry (bibtex-parse-entry t))
2142            (key (reftex-get-bib-field "=key=" entry))
2143            (pdf (format (concat org-ref-pdf-directory "%s.pdf") key)))
2144       (message "%s" pdf)
2145       (if (file-exists-p pdf)
2146           (org-open-link-from-string (format "[[file:%s]]" pdf))
2147         (ding)))))
2148
2149 ;; ** Open notes from bibtex entry
2150
2151 (defun org-ref-open-bibtex-notes ()
2152   "From a bibtex entry, open the notes if they exist, and create a heading if they do not.
2153
2154 I never did figure out how to use reftex to make this happen
2155 non-interactively. the reftex-format-citation function did not
2156 work perfectly; there were carriage returns in the strings, and
2157 it did not put the key where it needed to be. so, below I replace
2158 the carriage returns and extra spaces with a single space and
2159 construct the heading by hand."
2160   (interactive)
2161
2162   (bibtex-beginning-of-entry)
2163   (let* ((cb (current-buffer))
2164          (bibtex-expand-strings t)
2165          (entry (loop for (key . value) in (bibtex-parse-entry t)
2166                       collect (cons (downcase key) value)))
2167          (title (replace-regexp-in-string "\n\\|\t\\|\s+" " " (reftex-get-bib-field "title" entry)))
2168          (year  (reftex-get-bib-field "year" entry))
2169          (author (replace-regexp-in-string "\n\\|\t\\|\s+" " " (reftex-get-bib-field "author" entry)))
2170          (key (reftex-get-bib-field "=key=" entry))
2171          (journal (reftex-get-bib-field "journal" entry))
2172          (volume (reftex-get-bib-field "volume" entry))
2173          (pages (reftex-get-bib-field "pages" entry))
2174          (doi (reftex-get-bib-field "doi" entry))
2175          (url (reftex-get-bib-field "url" entry))
2176          )
2177
2178     ;; save key to clipboard to make saving pdf later easier by pasting.
2179     (with-temp-buffer
2180       (insert key)
2181       (kill-ring-save (point-min) (point-max)))
2182
2183     ;; now look for entry in the notes file
2184     (if  org-ref-bibliography-notes
2185         (find-file-other-window org-ref-bibliography-notes)
2186       (error "Org-ref-bib-bibliography-notes is not set to anything"))
2187
2188     (goto-char (point-min))
2189     ;; put new entry in notes if we don't find it.
2190     (if (re-search-forward (format ":Custom_ID: %s$" key) nil 'end)
2191         (funcall org-ref-open-notes-function)
2192       ;; no entry found, so add one
2193       (insert (format "\n** TODO %s - %s" year title))
2194       (insert (format"
2195  :PROPERTIES:
2196   :Custom_ID: %s
2197   :AUTHOR: %s
2198   :JOURNAL: %s
2199   :YEAR: %s
2200   :VOLUME: %s
2201   :PAGES: %s
2202   :DOI: %s
2203   :URL: %s
2204  :END:
2205 [[cite:%s]] [[file:%s/%s.pdf][pdf]]\n\n"
2206 key author journal year volume pages doi url key org-ref-pdf-directory key))
2207 (save-buffer))))
2208
2209 (defun org-ref-open-notes-from-reftex ()
2210   "Call reftex, and open notes for selected entry."
2211   (interactive)
2212   (let ((bibtex-key )))
2213
2214     ;; now look for entry in the notes file
2215     (if  org-ref-bibliography-notes
2216         (find-file-other-window org-ref-bibliography-notes)
2217       (error "Org-ref-bib-bibliography-notes is not set to anything"))
2218
2219     (goto-char (point-min))
2220
2221     (re-search-forward (format
2222                         ":Custom_ID: %s$"
2223                         (first (reftex-citation t)) nil 'end))
2224     (funcall org-ref-open-notes-function))
2225
2226 ;; ** Open bibtex entry in browser
2227 (defun org-ref-open-in-browser ()
2228   "Open the bibtex entry at point in a browser using the url field or doi field."
2229 (interactive)
2230 (save-excursion
2231   (bibtex-beginning-of-entry)
2232   (catch 'done
2233     (let ((url (bibtex-autokey-get-field "url")))
2234       (when  url
2235         (browse-url url)
2236         (throw 'done nil)))
2237
2238     (let ((doi (bibtex-autokey-get-field "doi")))
2239       (when doi
2240         (if (string-match "^http" doi)
2241             (browse-url doi)
2242           (browse-url (format "http://dx.doi.org/%s" doi)))
2243         (throw 'done nil)))
2244     (message "No url or doi found"))))
2245
2246 ;; ** upload entry to citeulike
2247
2248 (defun org-ref-upload-bibtex-entry-to-citeulike ()
2249   "With point in  a bibtex entry get bibtex string and submit to citeulike.
2250
2251 Relies on the python script /upload_bibtex_citeulike.py being in the user directory."
2252   (interactive)
2253   (message "uploading to citeulike")
2254   (save-restriction
2255     (bibtex-narrow-to-entry)
2256     (let ((startpos (point-min))
2257           (endpos (point-max))
2258           (bibtex-string (buffer-string))
2259           (script (concat "python " starter-kit-dir "/upload_bibtex_citeulike.py&")))
2260       (with-temp-buffer (insert bibtex-string)
2261                         (shell-command-on-region (point-min) (point-max) script t nil nil t)))))
2262
2263 ;; ** Build a pdf of the bibtex file
2264 (defun org-ref-build-full-bibliography ()
2265   "Build pdf of all bibtex entries, and open it."
2266   (interactive)
2267   (let* ((bibfile (file-name-nondirectory (buffer-file-name)))
2268         (bib-base (file-name-sans-extension bibfile))
2269         (texfile (concat bib-base ".tex"))
2270         (pdffile (concat bib-base ".pdf")))
2271     (find-file texfile)
2272     (erase-buffer)
2273     (insert (format "\\documentclass[12pt]{article}
2274 \\usepackage[version=3]{mhchem}
2275 \\usepackage{url}
2276 \\usepackage[numbers]{natbib}
2277 \\usepackage[colorlinks=true, linkcolor=blue, urlcolor=blue, pdfstartview=FitH]{hyperref}
2278 \\usepackage{doi}
2279 \\begin{document}
2280 \\nocite{*}
2281 \\bibliographystyle{unsrtnat}
2282 \\bibliography{%s}
2283 \\end{document}" bib-base))
2284     (save-buffer)
2285     (shell-command (concat "pdflatex " bib-base))
2286     (shell-command (concat "bibtex " bib-base))
2287     (shell-command (concat "pdflatex " bib-base))
2288     (shell-command (concat "pdflatex " bib-base))
2289     (kill-buffer texfile)
2290     (org-open-file pdffile)
2291     ))
2292
2293 ;; ** Extract bibtex entries in org-file
2294
2295 (defun org-ref-extract-bibtex-entries ()
2296   "Extract the bibtex entries referred to by cite links in the current buffer into a src block at the bottom of the current buffer.
2297
2298 If no bibliography is in the buffer the variable
2299 `reftex-default-bibliography' is used."
2300   (interactive)
2301   (let* ((temporary-file-directory (file-name-directory (buffer-file-name)))
2302          (tempname (make-temp-file "extract-bib"))
2303          (contents (buffer-string))
2304          (cb (current-buffer))
2305          basename texfile bibfile results)
2306
2307     ;; open tempfile and insert org-buffer contents
2308     (find-file tempname)
2309     (insert contents)
2310     (setq basename (file-name-sans-extension
2311                     (file-name-nondirectory buffer-file-name))
2312           texfile (concat tempname ".tex")
2313           bibfile (concat tempname ".bib"))
2314
2315     ;; see if we have a bibliography, and insert the default one if not.
2316     (save-excursion
2317       (goto-char (point-min))
2318       (unless (re-search-forward "^bibliography:" (point-max) 'end)
2319         (insert (format "\nbibliography:%s"
2320                         (mapconcat 'identity reftex-default-bibliography ",")))))
2321     (save-buffer)
2322
2323     ;; get a latex file and extract the references
2324     (org-latex-export-to-latex)
2325     (find-file texfile)
2326     (reftex-parse-all)
2327     (reftex-create-bibtex-file bibfile)
2328     (save-buffer)
2329     ;; save results of the references
2330     (setq results (buffer-string))
2331
2332     ;; kill buffers. these are named by basename, not full path
2333     (kill-buffer (concat basename ".bib"))
2334     (kill-buffer (concat basename ".tex"))
2335     (kill-buffer basename)
2336
2337     (delete-file bibfile)
2338     (delete-file texfile)
2339     (delete-file tempname)
2340
2341     ;; Now back to the original org buffer and insert the results
2342     (switch-to-buffer cb)
2343     (when (not (string= "" results))
2344       (save-excursion
2345         (goto-char (point-max))
2346         (insert "\n\n")
2347         (org-insert-heading)
2348         (insert (format " Bibtex entries
2349
2350 #+BEGIN_SRC text :tangle %s
2351 %s
2352 #+END_SRC" (concat (file-name-sans-extension (file-name-nondirectory (buffer-file-name))) ".bib") results))))))
2353
2354 ;; ** Find bad citations
2355 (require 'cl)
2356
2357 (defun index (substring list)
2358   "Return the index of SUBSTRING in a LIST of strings."
2359   (let ((i 0)
2360         (found nil))
2361     (dolist (arg list i)
2362       (if (string-match (concat "^" substring "$") arg)
2363           (progn
2364             (setq found t)
2365             (return i)))
2366       (setq i (+ i 1)))
2367     ;; return counter if found, otherwise return nil
2368     (if found i nil)))
2369
2370
2371 (defun org-ref-find-bad-citations ()
2372   "Create a list of citation keys in an org-file that do not have a bibtex entry in the known bibtex files.
2373
2374 Makes a new buffer with clickable links."
2375   (interactive)
2376   ;; generate the list of bibtex-keys and cited keys
2377   (let* ((bibtex-files (org-ref-find-bibliography))
2378          (bibtex-file-path (mapconcat (lambda (x) (file-name-directory (file-truename x))) bibtex-files ":"))
2379          (bibtex-keys (mapcar (lambda (x) (car x)) (bibtex-global-key-alist)))
2380          (bad-citations '()))
2381
2382     (org-element-map (org-element-parse-buffer) 'link
2383       (lambda (link)
2384         (let ((plist (nth 1 link)))
2385           (when (-contains? org-ref-cite-types (plist-get plist :type))
2386             (dolist (key (org-ref-split-and-strip-string (plist-get plist :path)))
2387               (when (not (index key bibtex-keys))
2388                 (setq
2389                  bad-citations
2390                  (append
2391                   bad-citations
2392                   `(,(format "%s [[elisp:(progn (switch-to-buffer-other-frame \"%s\")(goto-char %s))][not found here]]\n"
2393                              key
2394                              (buffer-name)
2395                              (plist-get plist :begin)))))
2396                 )))))
2397       ;; set with-affilates to t to get citations in a caption
2398       nil nil nil t)
2399
2400     (if bad-citations
2401       (progn
2402         (switch-to-buffer-other-window "*Missing citations*")
2403         (org-mode)
2404         (erase-buffer)
2405         (insert "* List of bad cite links\n")
2406         (insert (mapconcat 'identity bad-citations ""))
2407                                         ;(setq buffer-read-only t)
2408         (use-local-map (copy-keymap org-mode-map))
2409         (local-set-key "q" #'(lambda () (interactive) (kill-buffer))))
2410
2411       (when (get-buffer "*Missing citations*")
2412           (kill-buffer "*Missing citations*"))
2413       (message "No bad cite links found"))))
2414
2415 ;; ** helm interface to bad citations, labels, refs and files in orgfile
2416 (defun org-ref-bad-cite-candidates ()
2417   "Return a list of conses (key . marker) where key does not exist in the known bibliography files, and marker points to the key."
2418   (let* ((cp (point))                   ; save to return to later
2419          (bibtex-files (org-ref-find-bibliography))
2420          (bibtex-file-path (mapconcat
2421                             (lambda (x)
2422                               (file-name-directory (file-truename x)))
2423                             bibtex-files ":"))
2424          (bibtex-keys (mapcar (lambda (x) (car x))
2425                               (bibtex-global-key-alist)))
2426          (bad-citations '()))
2427
2428     (org-element-map (org-element-parse-buffer) 'link
2429       (lambda (link)
2430         (let ((plist (nth 1 link)))
2431           (when (-contains? org-ref-cite-types (plist-get plist :type))
2432             (dolist (key (org-ref-split-and-strip-string (plist-get plist :path)) )
2433               (when (not (index key bibtex-keys))
2434                 (goto-char (plist-get plist :begin))
2435                 (re-search-forward key)
2436                 (push (cons key (point-marker)) bad-citations)))
2437             )))
2438       ;; add with-affiliates to get cites in caption
2439       nil nil nil t)
2440     (goto-char cp)
2441     bad-citations))
2442
2443
2444 (defun org-ref-bad-ref-candidates ()
2445   "Return a list of conses (ref . marker) where ref is a ref link that does not point to anything (i.e. a label)."
2446   ;; first get a list of legitimate labels
2447   (let ((cp (point))
2448         (labels (org-ref-get-labels))
2449         (bad-refs '()))
2450     ;; now loop over ref links
2451     (goto-char (point-min))
2452     (org-element-map (org-element-parse-buffer) 'link
2453       (lambda (link)
2454         (let ((plist (nth 1 link)))
2455           (when (or  (equal (plist-get plist ':type) "ref")
2456                      (equal (plist-get plist ':type) "eqref")
2457                      (equal (plist-get plist ':type) "pageref")
2458                      (equal (plist-get plist ':type) "nameref"))
2459             (unless (-contains? labels (plist-get plist :path))
2460               (goto-char (plist-get plist :begin))
2461               (add-to-list
2462                'bad-refs
2463                (cons (plist-get plist :path)
2464                      (point-marker))))))))
2465     (goto-char cp)
2466     bad-refs))
2467
2468
2469 (defun org-ref-bad-label-candidates ()
2470   "Return a list of labels where label is multiply defined."
2471   (let ((labels (org-ref-get-labels))
2472         (multiple-labels '()))
2473     (when (not (= (length labels)
2474                   (length (-uniq labels))))
2475       (dolist (label labels)
2476         (when (> (-count (lambda (a)
2477                            (equal a label))
2478                          labels) 1)
2479           ;; this is a multiply defined label.
2480           (let ((cp (point)))
2481             (goto-char (point-min))
2482             (while (re-search-forward
2483                     (format  "[^#+]label:%s\\s-" label) nil t)
2484               (push (cons label (point-marker)) multiple-labels))
2485             (goto-char (point-min))
2486             (while (re-search-forward
2487                     (format  "\\label{%s}\\s-?" label) nil t)
2488               (push (cons label (point-marker)) multiple-labels))
2489
2490             (goto-char (point-min))
2491             (while (re-search-forward
2492                     (format  "^#\\+label:\\s-*%s" label) nil t)
2493               (push (cons label (point-marker)) multiple-labels))
2494
2495             (goto-char (point-min))
2496             (while (re-search-forward
2497                     (format   "^#\\+tblname:\\s-*%s" label) nil t)
2498               (push (cons label (point-marker)) multiple-labels))
2499             (goto-char cp)))))
2500       multiple-labels))
2501
2502 (defun org-ref-bad-file-link-candidates ()
2503   "Return list of conses (link . marker) wehre the file in the link does not exist."
2504   (let* ((bad-files '()))
2505     (org-element-map (org-element-parse-buffer) 'link
2506       (lambda (link)
2507         (let ((type (org-element-property :type link)))
2508           (when (or  (string= "file" type)
2509                      (string= "attachfile" type))
2510             (unless (file-exists-p (org-element-property :path link))
2511               (add-to-list 'bad-files
2512                            (cons (org-element-property :path link)
2513                                  (save-excursion
2514                                    (goto-char
2515                                     (org-element-property :begin link))
2516                                    (point-marker)))))))))
2517     ;; Let us also check \attachfile{fname}
2518     (save-excursion
2519       (goto-char (point-min))
2520       (while (re-search-forward "\\attachfile{\\(.*\\)}" nil t)
2521         (unless (file-exists-p (match-string 1))
2522           (add-to-list 'bad-files (cons (match-string 1) (point-marker))))))
2523     bad-files))
2524
2525 ;;;###autoload
2526 (defun org-ref ()
2527   "Opens a helm interface to actions for org-ref.
2528 Shows bad citations, ref links and labels"
2529   (interactive)
2530   (let ((cb (current-buffer))
2531         (bad-citations (org-ref-bad-cite-candidates))
2532         (bad-refs (org-ref-bad-ref-candidates))
2533         (bad-labels (org-ref-bad-label-candidates))
2534         (bad-files (org-ref-bad-file-link-candidates)))
2535
2536     (helm :sources `(((name . "Bad citations")
2537                        (candidates . ,bad-citations)
2538                        (action . (lambda (marker)
2539                                    (switch-to-buffer (marker-buffer marker))
2540                                    (goto-char marker))))
2541                      ;;
2542                      ((name . "Bad Labels")
2543                       (candidates . ,bad-labels)
2544                       (action . (lambda (marker)
2545                                    (switch-to-buffer (marker-buffer marker))
2546                                    (goto-char marker))))
2547                      ;;
2548                      ((name . "Bad ref links")
2549                       (candidates . ,bad-refs)
2550                       (action . (lambda (marker)
2551                                           (switch-to-buffer (marker-buffer marker))
2552                                           (goto-char marker))))
2553                      ;;
2554                      ((name . "Bad file links")
2555                       (candidates . ,bad-files)
2556                       (lambda (marker)
2557                                    (switch-to-buffer (marker-buffer marker))
2558                                    (goto-char marker)))
2559                      ;;
2560                      ((name . "Utilities")
2561                       (candidates . (("Check buffer again" . org-ref)
2562                                      ("Insert citation" . helm-bibtex)
2563                                      ("Insert label link" . org-ref-helm-insert-label-link)
2564                                      ("Insert ref link" . org-ref-helm-insert-ref-link)
2565                                      ("List of figures" . org-ref-list-of-figures)
2566                                      ("List of tables" . org-ref-list-of-tables)
2567                                      ("Table of contents" . nil)
2568                                      ))
2569                       (action . (lambda (x)
2570                                   (switch-to-buffer ,cb)
2571                                   (funcall x))))
2572                      ;;
2573                      ((name . "Export functions")
2574                       (candidates . (("Extract cited entries" . org-ref-extract-bibtex-entries)
2575                                      ("Export to html and open" . (lambda () (org-open-file (org-html-export-to-html))))
2576                                      ("Export to pdf and open" . (lambda ()
2577                                                                    (org-open-file (org-latex-export-to-pdf))))
2578                                      ("Export to manuscript pdf and open" . ox-manuscript-export-and-build-and-open)
2579                                      ("Export submission manuscript pdf and open" . ox-manuscript-build-submission-manuscript-and-open)
2580
2581                                      ))
2582                       (action . (lambda (x)
2583                                   (switch-to-buffer ,cb)
2584                                   (funcall x))))))))
2585
2586 ;; ** Find non-ascii charaters
2587 (defun org-ref-find-non-ascii-characters ()
2588   "Find non-ascii characters in the buffer.  Useful for cleaning up bibtex files."
2589   (interactive)
2590   (occur "[^[:ascii:]]"))
2591
2592 ;; ** Sort fields in a bibtex entry
2593
2594 (defun org-ref-sort-bibtex-entry ()
2595   "Sort fields of entry in standard order and downcase them."
2596   (interactive)
2597   (bibtex-beginning-of-entry)
2598   (let* ((master '("author" "title" "journal" "volume" "number" "pages" "year" "doi" "url"))
2599          (entry (bibtex-parse-entry))
2600          (entry-fields)
2601          (other-fields)
2602          (type (cdr (assoc "=type=" entry)))
2603          (key (cdr (assoc "=key=" entry))))
2604
2605     ;; these are the fields we want to order that are in this entry
2606     (setq entry-fields (mapcar (lambda (x) (car x)) entry))
2607     ;; we do not want to reenter these fields
2608     (setq entry-fields (remove "=key=" entry-fields))
2609     (setq entry-fields (remove "=type=" entry-fields))
2610
2611     ;;these are the other fields in the entry
2612     (setq other-fields (remove-if-not (lambda(x) (not (member x master))) entry-fields))
2613
2614     (cond
2615      ;; right now we only resort articles
2616      ((string= (downcase type) "article")
2617       (bibtex-kill-entry)
2618       (insert
2619        (concat "@article{" key ",\n"
2620                (mapconcat
2621                 (lambda (field)
2622                   (when (member field entry-fields)
2623                     (format "%s = %s," (downcase field) (cdr (assoc field entry))))) master "\n")
2624                (mapconcat
2625                 (lambda (field)
2626                   (format "%s = %s," (downcase field) (cdr (assoc field entry)))) other-fields "\n")
2627                "\n}\n\n"))
2628       (bibtex-find-entry key)
2629       (bibtex-fill-entry)
2630       (bibtex-clean-entry)
2631        ))))
2632
2633 ;; ** Clean a bibtex entry
2634 (defun org-ref-clean-bibtex-entry(&optional keep-key)
2635   "clean and replace the key in a bibtex function. When keep-key is t, do not replace it. You can use a prefix to specify the key should be kept"
2636   (interactive "P")
2637   (bibtex-beginning-of-entry)
2638 (end-of-line)
2639   ;; some entries do not have a key or comma in first line. We check and add it, if needed.
2640   (unless (string-match ",$" (thing-at-point 'line))
2641     (end-of-line)
2642     (insert ","))
2643
2644   ;; check for empty pages, and put eid or article id in its place
2645   (let ((entry (bibtex-parse-entry))
2646         (pages (bibtex-autokey-get-field "pages"))
2647         (year (bibtex-autokey-get-field "year"))
2648         (doi  (bibtex-autokey-get-field "doi"))
2649         ;; The Journal of Chemical Physics uses eid
2650         (eid (bibtex-autokey-get-field "eid")))
2651
2652     ;; replace http://dx.doi.org/ in doi. some journals put that in,
2653     ;; but we only want the doi.
2654     (when (string-match "^http://dx.doi.org/" doi)
2655       (bibtex-beginning-of-entry)
2656       (goto-char (car (cdr (bibtex-search-forward-field "doi" t))))
2657       (bibtex-kill-field)
2658       (bibtex-make-field "doi")
2659       (backward-char)
2660       (insert (replace-regexp-in-string "^http://dx.doi.org/" "" doi)))
2661
2662     ;; asap articles often set year to 0, which messes up key
2663     ;; generation. fix that.
2664     (when (string= "0" year)
2665       (bibtex-beginning-of-entry)
2666       (goto-char (car (cdr (bibtex-search-forward-field "year" t))))
2667       (bibtex-kill-field)
2668       (bibtex-make-field "year")
2669       (backward-char)
2670       (insert (read-string "Enter year: ")))
2671
2672     ;; fix pages if they are empty if there is an eid to put there.
2673     (when (string= "-" pages)
2674       (when eid
2675         (bibtex-beginning-of-entry)
2676         ;; this seems like a clunky way to set the pages field.But I
2677         ;; cannot find a better way.
2678         (goto-char (car (cdr (bibtex-search-forward-field "pages" t))))
2679         (bibtex-kill-field)
2680         (bibtex-make-field "pages")
2681         (backward-char)
2682         (insert eid)))
2683
2684     ;; replace naked & with \&
2685     (save-restriction
2686       (bibtex-narrow-to-entry)
2687       (bibtex-beginning-of-entry)
2688       (message "checking &")
2689       (replace-regexp " & " " \\\\& ")
2690       (widen))
2691
2692     ;; generate a key, and if it duplicates an existing key, edit it.
2693     (unless keep-key
2694       (let ((key (bibtex-generate-autokey)))
2695
2696         ;; first we delete the existing key
2697         (bibtex-beginning-of-entry)
2698         (re-search-forward bibtex-entry-maybe-empty-head)
2699         (if (match-beginning bibtex-key-in-head)
2700             (delete-region (match-beginning bibtex-key-in-head)
2701                            (match-end bibtex-key-in-head)))
2702         ;; check if the key is in the buffer
2703         (when (save-excursion
2704                 (bibtex-search-entry key))
2705           (save-excursion
2706             (bibtex-search-entry key)
2707             (bibtex-copy-entry-as-kill)
2708             (switch-to-buffer-other-window "*duplicate entry*")
2709             (bibtex-yank))
2710           (setq key (bibtex-read-key "Duplicate Key found, edit: " key)))
2711
2712         (insert key)
2713         (kill-new key))) ;; save key for pasting
2714
2715     ;; run hooks. each of these operates on the entry with no arguments.
2716     ;; this did not work like  i thought, it gives a symbolp error.
2717     ;; (run-hooks org-ref-clean-bibtex-entry-hook)
2718     (mapcar (lambda (x)
2719               (save-restriction
2720                 (save-excursion
2721                   (funcall x))))
2722             org-ref-clean-bibtex-entry-hook)
2723
2724     ;; sort fields within entry
2725     (org-ref-sort-bibtex-entry)
2726     ;; check for non-ascii characters
2727     (occur "[^[:ascii:]]")
2728     ))
2729
2730 (defun org-ref-get-citation-year (key)
2731   "Get the year of an entry with KEY.  Return year as a string."
2732   (let* ((results (org-ref-get-bibtex-key-and-file key))
2733          (bibfile (cdr results)))
2734     (with-temp-buffer
2735       (insert-file-contents bibfile)
2736       (bibtex-search-entry key nil 0)
2737       (prog1 (reftex-get-bib-field "year" (bibtex-parse-entry t))
2738         ))))
2739
2740 ;; ** Sort cite in cite link
2741 (defun org-ref-sort-citation-link ()
2742  "Replace link at point with sorted link by year."
2743  (interactive)
2744  (let* ((object (org-element-context))
2745         (type (org-element-property :type object))
2746         (begin (org-element-property :begin object))
2747         (end (org-element-property :end object))
2748         (link-string (org-element-property :path object))
2749         keys years data)
2750   (setq keys (org-ref-split-and-strip-string link-string))
2751   (setq years (mapcar 'org-ref-get-citation-year keys))
2752   (setq data (mapcar* (lambda (a b) `(,a . ,b)) years keys))
2753   (setq data (cl-sort data (lambda (x y) (< (string-to-int (car x)) (string-to-int (car y))))))
2754   ;; now get the keys separated by commas
2755   (setq keys (mapconcat (lambda (x) (cdr x)) data ","))
2756   ;; and replace the link with the sorted keys
2757   (cl--set-buffer-substring begin end (concat type ":" keys))))
2758
2759 ;; ** Shift-arrow sorting of keys in a cite link
2760
2761 (defun org-ref-swap-keys (i j keys)
2762  "Swap the KEYS in a list with index I and J."
2763  (let ((tempi (nth i keys)))
2764    (setf (nth i keys) (nth j keys))
2765    (setf (nth j keys) tempi))
2766   keys)
2767
2768
2769 (defun org-ref-swap-citation-link (direction)
2770  "Move citation at point in DIRECTION +1 is to the right, -1 to the left."
2771  (interactive)
2772  (let* ((object (org-element-context))
2773         (type (org-element-property :type object))
2774         (begin (org-element-property :begin object))
2775         (end (org-element-property :end object))
2776         (link-string (org-element-property :path object))
2777         key keys i)
2778    ;;   We only want this to work on citation links
2779    (when (-contains? org-ref-cite-types type)
2780         (setq key (org-ref-get-bibtex-key-under-cursor))
2781         (setq keys (org-ref-split-and-strip-string link-string))
2782         (setq i (index key keys))  ;; defined in org-ref
2783         (if (> direction 0) ;; shift right
2784             (org-ref-swap-keys i (+ i 1) keys)
2785           (org-ref-swap-keys i (- i 1) keys))
2786         (setq keys (mapconcat 'identity keys ","))
2787         ;; and replace the link with the sorted keys
2788         (cl--set-buffer-substring
2789          begin end
2790          (concat
2791           type ":" keys
2792           ;; It seems the space at the end can get consumed, so we see if there
2793           ;; is a space, and add it if so. Sometimes there is a comma or period,
2794           ;; then we do not want a space.
2795           (when
2796               (save-excursion
2797                 (goto-char end)
2798                 (looking-back " ")) " ")))
2799         ;; now go forward to key so we can move with the key
2800         (re-search-forward key)
2801         (goto-char (match-beginning 0)))))
2802
2803 ;; add hooks to make it work
2804 (add-hook 'org-shiftright-hook (lambda () (org-ref-swap-citation-link 1)))
2805 (add-hook 'org-shiftleft-hook (lambda () (org-ref-swap-citation-link -1)))
2806
2807 ;; ** context around org-ref links
2808 (defun org-ref-get-label-context (label)
2809   "Return a string of context around a LABEL."
2810   (save-excursion
2811     (catch 'result
2812       (goto-char (point-min))
2813       (when (re-search-forward
2814              (format "label:%s\\b" label) nil t)
2815         (throw 'result (buffer-substring
2816                         (progn
2817                           (previous-line)
2818                           (beginning-of-line)
2819                           (point))
2820                         (progn
2821                           (forward-line 4)
2822                           (point)))))
2823
2824       (goto-char (point-min))
2825       (when (re-search-forward
2826              (format "\\label{%s}" label) nil t)
2827         (throw 'result (buffer-substring
2828                         (progn
2829                           (previous-line)
2830                           (beginning-of-line)
2831                           (point))
2832                         (progn
2833                           (forward-line 4)
2834                           (point)))))
2835
2836       (goto-char (point-min))
2837       (when (re-search-forward
2838              (format "^#\\+label:\\s-*\\(%s\\)\\b" label) nil t)
2839         (throw 'result (buffer-substring
2840                         (progn
2841                           (previous-line)
2842                           (beginning-of-line)
2843                           (point))
2844                         (progn
2845                           (forward-line 4)
2846                           (point)))))
2847
2848       (goto-char (point-min))
2849       (when (re-search-forward
2850              (format "^#\\+tblname:\\s-*\\(%s\\)\\b" label) nil t)
2851         (throw 'result (buffer-substring
2852                         (progn
2853                           (previous-line)
2854                           (beginning-of-line)
2855                           (point))
2856                         (progn
2857                           (forward-line 4)
2858                           (point)))))
2859       (throw 'result "!!! NO CONTEXT FOUND !!!"))))
2860
2861
2862 (defun org-ref-link-message ()
2863   "Print a minibuffer message about the link that point is on."
2864   (interactive)
2865   (save-restriction
2866     (widen)
2867     (when (eq major-mode 'org-mode)
2868       (let* ((object (org-element-context))
2869              (type (org-element-property :type object)))
2870         (save-excursion
2871           (cond
2872            ;; cite links
2873            ((-contains? org-ref-cite-types type)
2874             (message (org-ref-get-citation-string-at-point)))
2875
2876            ;; message some context about the label we are referring to
2877            ((string= type "ref")
2878             (message "%scount: %s"
2879                      (org-ref-get-label-context
2880                       (org-element-property :path object))
2881                      (org-ref-count-labels
2882                       (org-element-property :path object))))
2883
2884            ((string= type "eqref")
2885             (message "%scount: %s"
2886                      (org-ref-get-label-context
2887                       (org-element-property :path object))
2888                      (org-ref-count-labels
2889                       (org-element-property :path object))))
2890
2891            ;; message the count
2892            ((string= type "label")
2893             (let ((count (org-ref-count-labels
2894                           (org-element-property :path object))))
2895               ;; get plurality on occurrence correct
2896               (message (concat
2897                         (number-to-string count)
2898                         " occurence"
2899                         (when (or (= count 0)
2900                                   (> count 1))
2901                           "s")))))
2902
2903            ((string= type "custom-id")
2904             (save-excursion
2905               (org-open-link-from-string
2906                (format "[[#%s]]" (org-element-property :path object)))
2907               (message "%s" (org-get-heading))))
2908
2909            ;; check if the bibliography files exist.
2910            ((string= type "bibliography")
2911             (let* ((bibfile)
2912                    ;; object is the link you clicked on
2913                    (object (org-element-context))
2914                    (link-string (org-element-property :path object))
2915                    (link-string-beginning)
2916                    (link-string-end))
2917               (save-excursion
2918                 (goto-char (org-element-property :begin object))
2919                 (search-forward link-string nil nil 1)
2920                 (setq link-string-beginning (match-beginning 0))
2921                 (setq link-string-end (match-end 0)))
2922
2923               ;; make sure we are in link and not before the :
2924               (when (> link-string-beginning (point))
2925                 (goto-char link-string-beginning))
2926
2927               ;; now if we have comma separated bibliographies
2928               ;; we find the one clicked on. we want to
2929               ;; search forward to next comma from point
2930               (save-excursion
2931                 (if (search-forward "," link-string-end 1 1)
2932                     (setq key-end (- (match-end 0) 1)) ; we found a match
2933                   (setq key-end (point)))) ; no comma found so take the point
2934
2935               ;; and backward to previous comma from point
2936               (save-excursion
2937                 (if (search-backward "," link-string-beginning 1 1)
2938                     (setq key-beginning (+ (match-beginning 0) 1)) ; we found a match
2939                   (setq key-beginning (point)))) ; no match found
2940               ;; save the key we clicked on.
2941               (setq bibfile
2942                     (org-ref-strip-string
2943                      (buffer-substring key-beginning key-end)))
2944               (if (file-exists-p bibfile)
2945                   (message "%s exists." bibfile)
2946                 (message "!!! %s NOT FOUND !!!" bibfile))))))))))
2947
2948 ;; ** aliases
2949 (defalias 'oro 'org-ref-open-citation-at-point)
2950 (defalias 'orc 'org-ref-citation-at-point)
2951 (defalias 'orp 'org-ref-open-pdf-at-point)
2952 (defalias 'oru 'org-ref-open-url-at-point)
2953 (defalias 'orn 'org-ref-open-notes-at-point)
2954 (defalias 'ornr 'org-ref-open-notes-from-reftex)
2955
2956 (defalias 'orib 'org-ref-insert-bibliography-link)
2957 (defalias 'oric 'org-ref-insert-cite-link)
2958 (defalias 'orir 'org-ref-insert-ref-link)
2959 (defalias 'orsl 'org-ref-store-bibtex-entry-link)
2960
2961 (defalias 'orcb 'org-ref-clean-bibtex-entry)
2962
2963 ;; * Helm bibtex setup
2964
2965 (setq helm-bibtex-additional-search-fields '(keywords))
2966
2967 (defun helm-bibtex-candidates-formatter (candidates source)
2968   "Formats BibTeX entries for display in results list.
2969 Argument CANDIDATES helm candidates.
2970 Argument SOURCE the helm source."
2971   (cl-loop
2972    with width = (with-helm-window (helm-bibtex-window-width))
2973    for entry in candidates
2974    for entry = (cdr entry)
2975    for entry-key = (helm-bibtex-get-value "=key=" entry)
2976    if (assoc-string "author" entry 'case-fold)
2977      for fields = '("author" "title" "year" "=has-pdf=" "=has-note=" "=type=")
2978    else
2979      for fields = '("editor" "title" "year" "=has-pdf=" "=has-note=" "=type=")
2980    for fields = (--map (helm-bibtex-clean-string
2981                         (helm-bibtex-get-value it entry " "))
2982                        fields)
2983    for fields = (-update-at 0 'helm-bibtex-shorten-authors fields)
2984    for fields = (append fields
2985                          (list  (or (helm-bibtex-get-value "keywords" entry)
2986                                     "" )))
2987    collect
2988    (cons (s-format "$0 $1 $2 $3 $4$5 $6" 'elt
2989                    (-zip-with (lambda (f w) (truncate-string-to-width f w 0 ?\s))
2990                               fields (list 36 (- width 85) 4 1 1 7 7)))
2991          entry-key)))
2992
2993 ;; * org-ref bibtex keywords
2994 ;; adapted from bibtex-utils.el
2995 ;; these are candidates for selecting keywords/tags
2996 (defun org-ref-bibtex-keywords ()
2997   "Get keywords defined in current bibtex file.
2998 These are in the keywords field, and are comma or semicolon separated."
2999   (save-excursion
3000     (goto-char (point-min))
3001     (let (keywords kstring)
3002       (while (re-search-forward "^\\s-*keywords.*{\\([^}]+\\)}" nil t)
3003         ;; TWS - remove newlines/multiple spaces:
3004         (setq kstring (replace-regexp-in-string "[ \t\n]+" " " (match-string 1)))
3005         (mapc
3006          (lambda (v)
3007            (add-to-list 'keywords v t))
3008          (split-string kstring "\\(,\\|;\\)[ \n]*\\|{\\|}" t)))
3009       keywords)))
3010
3011
3012 (defun org-ref-set-bibtex-keywords (keywords &optional arg)
3013   "Add KEYWORDS to a bibtex entry.
3014 If KEYWORDS is a list, it is converted to a comma-separated
3015 string.  The KEYWORDS are added to the beginning of the
3016 field.  Otherwise KEYWORDS should be a string of comma-separate
3017 keywords.  Optional argument ARG prefix arg to replace keywords."
3018   (interactive "sKeywords: \nP")
3019   (bibtex-set-field
3020    "keywords"
3021    (if arg
3022        ;; replace with arg
3023        (if (listp keywords)
3024            (mapconcat 'identity keywords ", ")
3025          keywords)
3026      ;; else concatentate
3027      (concat
3028       (if (listp keywords)
3029           (mapconcat 'identity keywords ", ")
3030         keywords)
3031       (when (not (string= "" (bibtex-autokey-get-field "keywords")))
3032         (concat ", "  (bibtex-autokey-get-field "keywords"))))))
3033   (save-buffer))
3034
3035
3036 (defun helm-tag-bibtex-entry ()
3037   "Helm interface to add keywords to a bibtex entry.
3038 Run this with the point in a bibtex entry."
3039   (interactive)
3040   (let ((keyword-source `((name . "Existing keywords")
3041                           (candidates . ,(org-ref-bibtex-keywords))
3042                           (action . (lambda (candidate)
3043                                       (org-ref-set-bibtex-keywords
3044                                        (mapconcat
3045                                         'identity
3046                                         (helm-marked-candidates)
3047                                         ", "))))))
3048         (fallback-source `((name . "Add new keywords")
3049                            (dummy)
3050                            (action . (lambda (candidate)
3051                                        (org-ref-set-bibtex-keywords helm-pattern)
3052                                        )))))
3053     (helm :sources '(keyword-source fallback-source))))
3054
3055 (defun helm-bibtex-show-entry (key)
3056   "Show the entry for KEY in the BibTeX file.
3057 The original function in `helm-bibtex' has a bug where it finds the
3058 first key that partially matches.  This version avoids that."
3059   (catch 'break
3060     (dolist (bibtex-file (if (listp helm-bibtex-bibliography)
3061                              helm-bibtex-bibliography
3062                            (list helm-bibtex-bibliography)))
3063       (let ((buf (helm-bibtex-buffer-visiting bibtex-file))
3064             (entries '()))
3065         (find-file bibtex-file)
3066         (bibtex-map-entries
3067          (lambda (key start end)
3068            (add-to-list 'entries (cons key start))))
3069         (if (assoc key entries)
3070             (progn
3071               (goto-char (cdr (assoc key entries)))
3072               (throw 'break t))
3073           (unless buf
3074             (kill-buffer)))))))
3075
3076 (defun org-ref-helm-tag-entries (candidates)
3077   "Set tags on selected bibtex entries from `helm-bibtex'.
3078 User is prompted for tags.  This function is called from `helm-bibtex'.
3079 Argument CANDIDATES helm candidates."
3080   (message "")
3081   (let ((keywords (read-string "Keywords (comma separated): ")))
3082     (loop for key in (helm-marked-candidates)
3083           do
3084           (save-window-excursion
3085             (helm-bibtex-show-entry key)
3086             (bibtex-set-field
3087              "keywords"
3088              (concat
3089               keywords
3090               ", " (bibtex-autokey-get-field "keywords")))
3091             (save-buffer)))))
3092
3093 (setq helm-source-bibtex
3094       '((name                                      . "BibTeX entries")
3095         (init                                      . helm-bibtex-init)
3096         (candidates                                . helm-bibtex-candidates)
3097         (filtered-candidate-transformer            . helm-bibtex-candidates-formatter)
3098         (action . (("Insert citation"              . helm-bibtex-insert-citation)
3099                    ("Show entry"                   . helm-bibtex-show-entry)
3100                    ("Open PDF file (if present)"   . helm-bibtex-open-pdf)
3101                    ("Open URL or DOI in browser"   . helm-bibtex-open-url-or-doi)
3102                    ("Insert formatted reference"   . helm-bibtex-insert-reference)
3103                    ("Insert BibTeX key"            . helm-bibtex-insert-key)
3104                    ("Insert BibTeX entry"          . helm-bibtex-insert-bibtex)
3105                    ("Attach PDF to email"          . helm-bibtex-add-PDF-attachment)
3106                    ("Edit notes"                   . helm-bibtex-edit-notes)
3107                    ("Add keywords to entries"      . org-ref-helm-tag-entries)
3108                    ))))
3109
3110 (defun helm-bibtex-format-org-ref (keys)
3111   "Insert selected KEYS as cite link. Append KEYS if you are on a link.
3112 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.
3113
3114 In the helm-bibtex buffer, C-u will give you a helm menu to select a new link type for the selected entries.
3115
3116 C-u C-u will change the key at point to the selected keys."
3117   (let* ((object (org-element-context))
3118          (last-char (save-excursion
3119                       (when (org-element-property :end object)
3120                         (goto-char (org-element-property :end object))
3121                         (unless (bobp)
3122                           (backward-char))
3123                         (if (looking-at " ")
3124                             " "
3125                           "")))))
3126     (cond
3127      ;; case where we are in a link
3128      ((and (equal (org-element-type object) 'link)
3129            (-contains?
3130             org-ref-cite-types
3131             (org-element-property :type object)))
3132       (cond
3133        ;; no prefix. append keys
3134        ((equal helm-current-prefix-arg nil)
3135         (goto-char (org-element-property :end object))
3136         (while (looking-back " ") (backward-char))
3137         (insert (concat "," (mapconcat 'identity keys ","))))
3138        ;; double prefix, replace key at point
3139        ((equal helm-current-prefix-arg '(16))
3140         (setf (buffer-substring
3141                (org-element-property :begin object)
3142                (org-element-property :end object))
3143               (concat
3144                (replace-regexp-in-string
3145                 (car (org-ref-get-bibtex-key-and-file)) ; key
3146                 (mapconcat 'identity keys ",")          ; new keys
3147                 (org-element-property :raw-link object))
3148                ;; replace space at end to avoid collapsing into next word.
3149                last-char))
3150         ;; and we want to go to the end of the new link
3151         (goto-char
3152          (org-element-property :end (org-element-context))))
3153        (t
3154         (message "Not found"))))
3155
3156      ;; We are next to a link, and we want to append
3157      ;; next to a link means one character back is on a link.
3158      ((save-excursion
3159         (unless (bobp) (backward-char))
3160         (and (equal (org-element-type (org-element-context)) 'link)
3161              (-contains?
3162               org-ref-cite-types
3163               (org-element-property :type (org-element-context)))))
3164       (while (looking-back " ") (backward-char))
3165       (insert (concat "," (mapconcat 'identity keys ","))))
3166
3167      ;; insert fresh link
3168      (t
3169       ;;(message-box "fresh link")
3170       (insert
3171        (concat (if (equal helm-current-prefix-arg '(4))
3172                    (helm :sources `((name . "link types")
3173                                     (candidates . ,org-ref-cite-types)
3174                                     (action . (lambda (x) x))))
3175                org-ref-default-citation-link)
3176                ":"
3177                (s-join "," keys))))))
3178   ;; return empty string for helm
3179   "")
3180
3181 (setq helm-bibtex-format-citation-functions
3182       '((org-mode . helm-bibtex-format-org-ref)))
3183
3184 ;;;###autoload
3185 (defun org-ref-helm-insert-cite-link (arg)
3186   "org-ref function to use helm-bibtex to insert a citation link.
3187 With one prefix arg, insert a ref link.
3188 With two prefix args, insert a label link."
3189   (interactive "P")
3190   (cond
3191    ((equal arg nil)
3192      (let ((helm-bibtex-bibliography (org-ref-find-bibliography)))
3193        (helm-bibtex)))
3194    ((equal arg '(4))
3195     (org-ref-helm-insert-ref-link))
3196    ((equal arg '(16))
3197     (org-ref-helm-insert-label-link))))
3198
3199
3200 ;; add our own fallback entries where we want them. These appear in reverse order of adding in the menu
3201 (setq helm-bibtex-fallback-options
3202       (-insert-at 1 '("Crossref" . "http://search.crossref.org/?q=%s") helm-bibtex-fallback-options))
3203
3204 (setq helm-bibtex-fallback-options
3205       (-insert-at
3206        1
3207        '("Scopus" . "http://www.scopus.com/scopus/search/submit/xadvanced.url?searchfield=TITLE-ABS-KEY(%s)")
3208        helm-bibtex-fallback-options))
3209
3210 (setq helm-bibtex-fallback-options
3211       (-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))
3212
3213 (defun org-ref-get-citation-string-at-point ()
3214   "Get a string of a formatted citation."
3215   (let* ((results (org-ref-get-bibtex-key-and-file))
3216          (key (car results))
3217          (bibfile (cdr results)))
3218     (if bibfile
3219         (save-excursion
3220           (with-temp-buffer
3221             (insert-file-contents bibfile)
3222             (bibtex-search-entry key)
3223             (org-ref-bib-citation)))
3224       "!!! No entry found !!!" )))
3225
3226
3227 (defun org-ref-cite-candidates ()
3228   "Generate the list of possible candidates for click actions on a cite link.
3229 Checks for pdf and doi, and add appropriate functions."
3230   (let* ((results (org-ref-get-bibtex-key-and-file))
3231          (key (car results))
3232          (pdf-file (format (concat org-ref-pdf-directory "%s.pdf") key))
3233          (bibfile (cdr results))
3234          (url (save-excursion
3235                 (with-temp-buffer
3236                   (insert-file-contents bibfile)
3237                   (bibtex-search-entry key)
3238                   (bibtex-autokey-get-field "url"))))
3239          (doi (save-excursion
3240                 (with-temp-buffer
3241                   (insert-file-contents bibfile)
3242                   (bibtex-search-entry key)
3243                   ;; I like this better than bibtex-url which does not always find
3244                   ;; the urls
3245                   (bibtex-autokey-get-field "doi"))))
3246          (candidates `(("Quit" . org-ref-citation-at-point)
3247                        ("Open bibtex entry" . org-ref-open-citation-at-point))))
3248     ;; for some reason, when there is no doi or url, they are returned as "". I
3249     ;; prefer nil so we correct this here.
3250     (when (string= doi "") (setq doi nil))
3251     (when (string= url "") (setq url nil))
3252
3253     ;; Conditional pdf functions
3254     (if (file-exists-p pdf-file)
3255         (add-to-list
3256          'candidates
3257          '("Open pdf" . org-ref-open-pdf-at-point)
3258          t)
3259       (add-to-list
3260        'candidates
3261        '("Try to get pdf" . (lambda ()
3262                               (save-window-excursion
3263                                 (org-ref-open-citation-at-point)
3264                                 (bibtex-beginning-of-entry)
3265                                 (doi-utils-get-bibtex-entry-pdf))))
3266        t))
3267
3268
3269     (add-to-list
3270      'candidates
3271      '("Open notes" . org-ref-open-notes-at-point)
3272      t)
3273
3274     ;; conditional url and doi functions
3275     (when (or url doi)
3276       (add-to-list
3277        'candidates
3278        '("Open in browser" . org-ref-open-url-at-point)
3279        t))
3280
3281     (when doi
3282       (mapc (lambda (x)
3283               (add-to-list 'candidates x t))
3284             `(("WOS" . org-ref-wos-at-point)
3285               ("Related articles in WOS" . org-ref-wos-related-at-point)
3286               ("Citing articles in WOS" . org-ref-wos-citing-at-point)
3287               ("Google Scholar" . org-ref-google-scholar-at-point)
3288               ("Pubmed" . org-ref-pubmed-at-point)
3289               ("Crossref" . org-ref-crossref-at-point)
3290               )))
3291
3292     (add-to-list
3293      'candidates
3294      '("Copy formatted citation to clipboard" . org-ref-copy-entry-as-summary)
3295      t)
3296
3297     (add-to-list
3298      'candidates
3299      '("Copy key to clipboard" . (lambda ()
3300                                   (kill-new
3301                                    (car (org-ref-get-bibtex-key-and-file)))))
3302      t)
3303
3304     (add-to-list
3305      'candidates
3306      '("Copy bibtex entry to file" . org-ref-copy-entry-at-point-to-file)
3307      t)
3308
3309     (add-to-list
3310      'candidates
3311      '("Email bibtex entry and pdf" . (lambda ()
3312                   (save-excursion
3313                     (org-ref-open-citation-at-point)
3314                     (email-bibtex-entry))))
3315      t)
3316   ;; finally return a numbered list of the candidates
3317   (loop for i from 0
3318         for cell in candidates
3319         collect (cons (format "%2s. %s" i (car cell))
3320                       (cdr cell)))))
3321
3322
3323 (defvar org-ref-helm-user-candidates '()
3324   "List of user-defined candidates to act when clicking on a cite link.
3325 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.")
3326
3327 ;; example of adding your own function
3328 (add-to-list
3329  'org-ref-helm-user-candidates
3330  '("Example" . (lambda () (message-box "You did it!")))
3331  t)
3332
3333 ;;;###autoload
3334 (defun org-ref-cite-click-helm (key)
3335   "Open helm for actions on a cite link.
3336 subtle points.
3337
3338 1. get name and candidates before entering helm because we need
3339 the org-buffer.
3340
3341 2. switch back to the org buffer before evaluating the
3342 action.  most of them need the point and buffer.
3343
3344 KEY is returned for the selected item(s) in helm."
3345   (interactive)
3346   (let ((name (org-ref-get-citation-string-at-point))
3347         (candidates (org-ref-cite-candidates))
3348         (cb (current-buffer)))
3349
3350     (helm :sources `(((name . ,name)
3351                       (candidates . ,candidates)
3352                       (action . (lambda (f)
3353                                   (switch-to-buffer cb)
3354                                   (funcall f))))
3355                      ((name . "User functions")
3356                       (candidates . ,org-ref-helm-user-candidates)
3357                       (action . (lambda (f)
3358                                   (switch-to-buffer cb)
3359                                   (funcall f))))
3360                      ))))
3361
3362 ;; * Hydra menus in org-ref
3363
3364 (when (featurep 'hydra)
3365   (require 'hydra)
3366   (setq hydra-is-helpful t)
3367
3368   (defhydra org-ref-cite-hydra (:color blue)
3369     "
3370 _p_: Open pdf     _w_: WOS          _g_: Google Scholar _K_: Copy citation to clipboard
3371 _u_: Open url     _r_: WOS related  _P_: Pubmed         _k_: Copy key to clipboard
3372 _n_: Open notes   _c_: WOS citing   _C_: Crossref       _f_: Copy bibtex entry to file
3373 _o_: Open entry   _e_: Email entry and pdf
3374 "
3375     ("o" org-ref-open-citation-at-point nil)
3376     ("p" org-ref-open-pdf-at-point nil)
3377     ("n" org-ref-open-notes-at-point nil)
3378     ("u" org-ref-open-url-at-point nil)
3379     ("w" org-ref-wos-at-point nil)
3380     ("r" org-ref-wos-related-at-point nil)
3381     ("c" org-ref-wos-citing-at-point nil)
3382     ("g" org-ref-google-scholar-at-point nil)
3383     ("P" org-ref-pubmed-at-point nil)
3384     ("C" org-ref-crossref-at-point nil)
3385     ("K" org-ref-copy-entry-as-summary nil)
3386     ("k" (progn
3387            (kill-new
3388             (car (org-ref-get-bibtex-key-and-file)))) nil)
3389     ("f" org-ref-copy-entry-at-point-to-file nil)
3390
3391     ("e" (save-excursion
3392            (org-ref-open-citation-at-point)
3393            (email-bibtex-entry)) nil)))
3394
3395 ;; * org-ref-help
3396 (defun org-ref-help ()
3397   "Open the org-ref manual."
3398   (interactive)
3399   (find-file (expand-file-name
3400               "org-ref.org"
3401               (file-name-directory
3402                (find-library-name "org-ref")))))
3403
3404 ;; * org-ref menu
3405 (defun org-ref-org-menu ()
3406   "Add org-ref menu to the Org menu."
3407
3408   (easy-menu-change
3409    '("Org") "org-ref"
3410    '( ["Insert citation" org-ref-helm-insert-cite-link]
3411       ["Insert ref" org-ref-helm-insert-ref-link]
3412       ["Insert label" org-ref-helm-insert-label-link]
3413       "--"
3414       ["List of figures" org-ref-list-of-figures]
3415       ["List of tables" org-ref-list-of-tables]
3416       ["Extract bibtex entries" org-ref-extract-bibtex-entries]
3417       ["Check org-file" org-ref]
3418       "--"
3419       ["Help" org-ref-help]
3420       ["Customize org-ref" (customize-group 'org-ref)])
3421    "Show/Hide")
3422
3423   (easy-menu-change '("Org") "--" nil "Show/Hide"))
3424
3425 (add-hook 'org-mode-hook 'org-ref-org-menu)
3426
3427 ;; * The end
3428 (provide 'org-ref)
3429
3430 ;;; org-ref.el ends here