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