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