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