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