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