]> git.donarmstrong.com Git - org-ref.git/blob - org-ref.el
minor space removal
[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 'latex) (format "\\eqref{%s}" keyword))
1427     ;;considering the fact that latex's the standard of math formulas, just use mathjax to render the html
1428     ;;customize the variable 'org-html-mathjax-template' and 'org-html-mathjax-options' refering to  'autonumber'
1429     ((eq format 'html) (format "\\eqref{%s}" keyword)))))
1430
1431 ;; ** cite link
1432
1433 (defun org-ref-get-bibtex-key-under-cursor ()
1434   "Return key under the bibtex cursor.
1435 We search forward from
1436 point to get a comma, or the end of the link, and then backwards
1437 to get a comma, or the beginning of the link.  that delimits the
1438 keyword we clicked on.  We also strip the text properties."
1439   (let* ((object (org-element-context))
1440          (link-string (org-element-property :path object)))
1441     ;; you may click on the part before the citations. here we make
1442     ;; sure to move to the beginning so you get the first citation.
1443     (let ((cp (point)))
1444       (goto-char (org-element-property :begin object))
1445       (search-forward link-string (org-element-property :end object))
1446       (goto-char (match-beginning 0))
1447       ;; check if we clicked before the path and move as needed.
1448       (unless (< cp (point))
1449         (goto-char cp)))
1450
1451     (if (not (org-element-property :contents-begin object))
1452         ;; this means no description in the link
1453         (progn
1454           ;; we need the link path start and end
1455           (let (link-string-beginning link-string-end)
1456             (save-excursion
1457               (goto-char (org-element-property :begin object))
1458               (search-forward link-string nil nil 1)
1459               (setq link-string-beginning (match-beginning 0))
1460               (setq link-string-end (match-end 0)))
1461
1462             (let (key-beginning key-end)
1463               ;; The key is the text between commas, or the link boundaries
1464               (save-excursion
1465                 (if (search-forward "," link-string-end t 1)
1466                     (setq key-end (- (match-end 0) 1)) ; we found a match
1467                   (setq key-end link-string-end))) ; no comma found so take the end
1468               ;; and backward to previous comma from point which defines the start character
1469               (save-excursion
1470                 (if (search-backward "," link-string-beginning 1 1)
1471                     (setq key-beginning (+ (match-beginning 0) 1)) ; we found a match
1472                   (setq key-beginning link-string-beginning))) ; no match found
1473               ;; save the key we clicked on.
1474               (let ((bibtex-key
1475                      (org-ref-strip-string
1476                       (buffer-substring key-beginning key-end))))
1477                 (set-text-properties 0 (length bibtex-key) nil bibtex-key)
1478                 bibtex-key))))
1479       ;; link with description. assume only one key
1480       link-string)))
1481
1482 (defun org-ref-find-bibliography ()
1483   "Find the bibliography in the buffer.
1484 This function sets and returns cite-bibliography-files, which is a list of files
1485 either from bibliography:f1.bib,f2.bib
1486 \bibliography{f1,f2}
1487 internal bibliographies
1488
1489 falling back to what the user has set in `org-ref-default-bibliography'"
1490   (catch 'result
1491     (save-excursion
1492       (goto-char (point-min))
1493       ;;  look for a bibliography link
1494       (when (re-search-forward "\\<bibliography:\\([^\]\|\n]+\\)" nil t)
1495         (setq org-ref-bibliography-files
1496               (mapcar 'org-ref-strip-string (split-string (match-string 1) ",")))
1497         (throw 'result org-ref-bibliography-files))
1498
1499
1500       ;; we did not find a bibliography link. now look for \bibliography
1501       (goto-char (point-min))
1502       (when (re-search-forward "\\\\bibliography{\\([^}]+\\)}" nil t)
1503         ;; split, and add .bib to each file
1504         (setq org-ref-bibliography-files
1505               (mapcar (lambda (x) (concat x ".bib"))
1506                       (mapcar 'org-ref-strip-string
1507                               (split-string (match-string 1) ","))))
1508         (throw 'result org-ref-bibliography-files))
1509
1510       ;; no bibliography found. maybe we need a biblatex addbibresource
1511       (goto-char (point-min))
1512       ;;  look for a bibliography link
1513       (when (re-search-forward "addbibresource:\\([^\]\|\n]+\\)" nil t)
1514         (setq org-ref-bibliography-files
1515               (mapcar 'org-ref-strip-string (split-string (match-string 1) ",")))
1516         (throw 'result org-ref-bibliography-files))
1517
1518       ;; we did not find anything. use defaults
1519       (setq org-ref-bibliography-files org-ref-default-bibliography)))
1520
1521     ;; set reftex-default-bibliography so we can search
1522     (set (make-local-variable 'reftex-default-bibliography) org-ref-bibliography-files)
1523     org-ref-bibliography-files)
1524
1525 (defun org-ref-key-in-file-p (key filename)
1526   "Determine if the KEY is in the FILENAME."
1527   (save-current-buffer
1528     (let ((bibtex-files (list filename)))
1529       ;; This is something I am trying because when the bibtex file is open, and
1530       ;; you have added to it, the only way I find to get the update to update
1531       ;; is to close it and reopen it. or to save it and revert it.
1532       (when (get-file-buffer filename)
1533         (set-buffer (get-file-buffer filename))
1534         (save-buffer)
1535         (revert-buffer t t))
1536       (bibtex-search-entry key t))))
1537
1538 (defun org-ref-get-bibtex-key-and-file (&optional key)
1539   "Return the bibtex KEY and file that it is in.  If no key is provided, get one under point."
1540  (let ((org-ref-bibliography-files (org-ref-find-bibliography))
1541        (file))
1542    (unless key
1543      (setq key (org-ref-get-bibtex-key-under-cursor)))
1544    (setq file     (catch 'result
1545                     (cl-loop for file in org-ref-bibliography-files do
1546                              (if (org-ref-key-in-file-p key (file-truename file))
1547                                  (throw 'result file)))))
1548    (cons key file)))
1549
1550 ;; *** key at point functions
1551
1552 (defun org-ref-get-pdf-filename (key)
1553   "Return the pdf filename associated with a bibtex KEY."
1554   (format (concat org-ref-pdf-directory "%s.pdf") key))
1555
1556
1557 (defun org-ref-get-mendeley-filename (key)
1558   "Return the pdf filename indicated by mendeley file field.
1559 Falls back to org-ref-get-pdf-filename if file filed does not exist.
1560 Contributed by https://github.com/autosquid."
1561   (let* ((results (org-ref-get-bibtex-key-and-file key))
1562          (bibfile (cdr results)))
1563     (with-temp-buffer
1564       (insert-file-contents bibfile)
1565       (bibtex-set-dialect (parsebib-find-bibtex-dialect) t)
1566       (bibtex-search-entry key nil 0)
1567       (setq entry (bibtex-parse-entry))
1568       (let ((e (org-ref-reftex-get-bib-field "file" entry)))
1569         (if (> (length e) 4)
1570             (remove-if
1571              (lambda (ch)
1572                (find ch "{}\\"))
1573              (format "/%s" (subseq e 1 (- (length e) 4))))
1574           (format (concat org-ref-pdf-directory "%s.pdf") key))))))
1575
1576
1577 (defun org-ref-open-pdf-at-point ()
1578   "Open the pdf for bibtex key under point if it exists."
1579   (interactive)
1580   (let* ((results (org-ref-get-bibtex-key-and-file))
1581          (key (car results))
1582          (pdf-file (funcall org-ref-get-pdf-filename-function key)))
1583     (if (file-exists-p pdf-file)
1584         (org-open-file pdf-file)
1585 (message "no pdf found for %s" key))))
1586
1587
1588 (defun org-ref-open-url-at-point ()
1589   "Open the url for bibtex key under point."
1590   (interactive)
1591   (let* ((results (org-ref-get-bibtex-key-and-file))
1592          (key (car results))
1593          (bibfile (cdr results)))
1594     (save-excursion
1595       (with-temp-buffer
1596         (insert-file-contents bibfile)
1597         (bibtex-set-dialect (parsebib-find-bibtex-dialect) t)
1598         (bibtex-search-entry key)
1599         ;; I like this better than bibtex-url which does not always find
1600         ;; the urls
1601         (catch 'done
1602           (let ((url (bibtex-autokey-get-field "url")))
1603             (when  url
1604               (browse-url (s-trim url))
1605               (throw 'done nil)))
1606
1607           (let ((doi (bibtex-autokey-get-field "doi")))
1608             (when doi
1609               (if (string-match "^http" doi)
1610                   (browse-url doi)
1611                 (browse-url (format "http://dx.doi.org/%s" (s-trim doi))))
1612               (throw 'done nil))))))))
1613
1614
1615 (defun org-ref-open-notes-at-point ()
1616   "Open the notes for bibtex key under point."
1617   (interactive)
1618   (let* ((results (org-ref-get-bibtex-key-and-file))
1619          (key (car results))
1620          (bibfile (cdr results)))
1621     (save-excursion
1622       (with-temp-buffer
1623         (insert-file-contents bibfile)
1624         (bibtex-set-dialect (parsebib-find-bibtex-dialect) t)
1625         (bibtex-search-entry key)
1626         (org-ref-open-bibtex-notes)))))
1627
1628
1629 (defun org-ref-citation-at-point ()
1630   "Give message of current citation at point."
1631   (interactive)
1632   (let* ((cb (current-buffer))
1633         (results (org-ref-get-bibtex-key-and-file))
1634         (key (car results))
1635         (bibfile (cdr results)))
1636     (message "%s" (progn
1637                     (with-temp-buffer
1638                       (insert-file-contents bibfile)
1639                       (bibtex-set-dialect (parsebib-find-bibtex-dialect) t)
1640                       (bibtex-search-entry key)
1641                       (org-ref-bib-citation))))))
1642
1643
1644 (defun org-ref-open-citation-at-point ()
1645   "Open bibtex file to key at point."
1646   (interactive)
1647   (let* ((cb (current-buffer))
1648         (results (org-ref-get-bibtex-key-and-file))
1649         (key (car results))
1650         (bibfile (cdr results)))
1651     (find-file bibfile)
1652     (bibtex-search-entry key)))
1653
1654 ;; *** cite menu
1655
1656 (defvar org-ref-cite-menu-funcs '()
1657  "Functions to run on cite click menu.
1658 Each entry is a list of (key menu-name function).
1659 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.")
1660
1661
1662 (defvar org-ref-user-cite-menu-funcs
1663   '(("C" "rossref" org-ref-crossref-at-point)
1664     ("y" "Copy entry to file" org-ref-copy-entry-at-point-to-file)
1665     ("s" "Copy summary" org-ref-copy-entry-as-summary))
1666   "User-defined functions to run on bibtex key at point.")
1667
1668
1669 (defun org-ref-copy-entry-as-summary ()
1670   "Copy the bibtex entry for the citation at point as a summary."
1671   (interactive)
1672     (save-window-excursion
1673       (org-ref-open-citation-at-point)
1674       (kill-new (org-ref-bib-citation))))
1675
1676
1677 (defun org-ref-copy-entry-at-point-to-file ()
1678   "Copy the bibtex entry for the citation at point to NEW-FILE.
1679 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."
1680   (interactive)
1681   (let ((new-file (ido-completing-read
1682                    "Copy to bibfile: "
1683                    (append org-ref-default-bibliography
1684                            (f-entries "." (lambda (f) (f-ext? f "bib"))))))
1685         (key (org-ref-get-bibtex-key-under-cursor)))
1686     (save-window-excursion
1687       (org-ref-open-citation-at-point)
1688       (bibtex-copy-entry-as-kill))
1689
1690     (let ((bibtex-files (list (file-truename new-file))))
1691       (if (assoc key (bibtex-global-key-alist))
1692           (message "That key already exists in %s" new-file)
1693         ;; add to file
1694         (save-window-excursion
1695           (find-file new-file)
1696           (goto-char (point-max))
1697           ;; make sure we are at the beginning of a line.
1698           (unless (looking-at "^") (insert "\n\n"))
1699           (bibtex-yank)
1700           (save-buffer))))))
1701
1702
1703 (defun org-ref-get-doi-at-point ()
1704   "Get doi for key at point."
1705   (let* ((results (org-ref-get-bibtex-key-and-file))
1706          (key (car results))
1707          (bibfile (cdr results))
1708          doi)
1709     (save-excursion
1710       (with-temp-buffer
1711         (insert-file-contents bibfile)
1712         (bibtex-set-dialect (parsebib-find-bibtex-dialect) t)
1713         (bibtex-search-entry key)
1714         (setq doi (bibtex-autokey-get-field "doi"))
1715         ;; in case doi is a url, remove the url part.
1716         (replace-regexp-in-string "^http://dx.doi.org/" "" doi)))))
1717
1718
1719 ;; **** functions that operate on key at point for click menu
1720 (defun org-ref-wos-at-point ()
1721   "Open the doi in wos for bibtex key under point."
1722   (interactive)
1723   (doi-utils-wos (org-ref-get-doi-at-point)))
1724
1725
1726 (defun org-ref-wos-citing-at-point ()
1727   "Open the doi in wos citing articles for bibtex key under point."
1728   (interactive)
1729   (doi-utils-wos-citing (org-ref-get-doi-at-point)))
1730
1731
1732 (defun org-ref-wos-related-at-point ()
1733   "Open the doi in wos related articles for bibtex key under point."
1734   (interactive)
1735   (doi-utils-wos-related (org-ref-get-doi-at-point)))
1736
1737
1738 (defun org-ref-google-scholar-at-point ()
1739   "Open the doi in google scholar for bibtex key under point."
1740   (interactive)
1741   (doi-utils-google-scholar (org-ref-get-doi-at-point)))
1742
1743
1744 (defun org-ref-pubmed-at-point ()
1745   "Open the doi in pubmed for bibtex key under point."
1746   (interactive)
1747   (doi-utils-pubmed (org-ref-get-doi-at-point)))
1748
1749
1750 (defun org-ref-crossref-at-point ()
1751   "Open the doi in crossref for bibtex key under point."
1752   (interactive)
1753   (doi-utils-crossref (org-ref-get-doi-at-point)))
1754
1755 ;; *** Minibuffer menu
1756
1757 (defun org-ref-cite-onclick-minibuffer-menu (&optional link-string)
1758   "Action when a cite link is clicked on.
1759 Provides a menu of context sensitive actions.  If the bibtex entry
1760 has a pdf, you get an option to open it.  If there is a doi, you
1761 get a lot of options.  LINK-STRING is used by the link function."
1762   (interactive)
1763   (let* ((results (org-ref-get-bibtex-key-and-file))
1764          (key (car results))
1765          (pdf-file (funcall org-ref-get-pdf-filename-function key))
1766          (bibfile (cdr results))
1767          (url (save-excursion
1768                 (with-temp-buffer
1769                   (insert-file-contents bibfile)
1770                   (bibtex-set-dialect (parsebib-find-bibtex-dialect) t)
1771                   (bibtex-search-entry key)
1772                   (bibtex-autokey-get-field "url"))))
1773          (doi (save-excursion
1774                 (with-temp-buffer
1775                   (insert-file-contents bibfile)
1776                   (bibtex-set-dialect (parsebib-find-bibtex-dialect) t)
1777                   (bibtex-search-entry key)
1778                   ;; I like this better than bibtex-url which does not always find
1779                   ;; the urls
1780                   (bibtex-autokey-get-field "doi")))))
1781
1782     (when (string= "" doi) (setq doi nil))
1783     (when (string= "" url) (setq url nil))
1784     (setq org-ref-cite-menu-funcs '())
1785
1786     ;; open action
1787     (when
1788         bibfile
1789       (add-to-list
1790        'org-ref-cite-menu-funcs
1791        '("o" "pen" org-ref-open-citation-at-point)))
1792
1793     ;; pdf
1794     (when (file-exists-p pdf-file)
1795       (add-to-list
1796        'org-ref-cite-menu-funcs
1797        `("p" "df" ,org-ref-open-pdf-function) t))
1798
1799     ;; notes
1800     (add-to-list
1801      'org-ref-cite-menu-funcs
1802      '("n" "otes" org-ref-open-notes-at-point) t)
1803
1804     ;; url
1805     (when (or url doi)
1806       (add-to-list
1807        'org-ref-cite-menu-funcs
1808        '("u" "rl" org-ref-open-url-at-point) t))
1809
1810     ;; doi funcs
1811     (when doi
1812       (add-to-list
1813        'org-ref-cite-menu-funcs
1814        '("w" "os" org-ref-wos-at-point) t)
1815
1816       (add-to-list
1817        'org-ref-cite-menu-funcs
1818        '("c" "iting" org-ref-wos-citing-at-point) t)
1819
1820       (add-to-list
1821        'org-ref-cite-menu-funcs
1822        '("r" "elated" org-ref-wos-related-at-point) t)
1823
1824       (add-to-list
1825        'org-ref-cite-menu-funcs
1826        '("g" "oogle scholar" org-ref-google-scholar-at-point) t)
1827
1828       (add-to-list
1829        'org-ref-cite-menu-funcs
1830        '("P" "ubmed" org-ref-pubmed-at-point) t))
1831
1832     ;; add user functions
1833     (dolist (tup org-ref-user-cite-menu-funcs)
1834       (add-to-list
1835        'org-ref-cite-menu-funcs
1836        tup t))
1837
1838     ;; finally quit
1839     (add-to-list
1840      'org-ref-cite-menu-funcs
1841      '("q" "uit" (lambda ())) t)
1842
1843     ;; now we make a menu
1844     ;; construct menu string as a message
1845     (message
1846      (concat
1847       (let* ((results (org-ref-get-bibtex-key-and-file))
1848              (key (car results))
1849              (bibfile (cdr results)))
1850         (save-excursion
1851           (with-temp-buffer
1852             (insert-file-contents bibfile)
1853             (bibtex-set-dialect (parsebib-find-bibtex-dialect) t)
1854             (bibtex-search-entry key)
1855             (org-ref-bib-citation))))
1856       "\n"
1857       (mapconcat
1858        (lambda (tup)
1859          (concat "[" (elt tup 0) "]"
1860                  (elt tup 1) " "))
1861        org-ref-cite-menu-funcs "")))
1862     ;; get the input
1863     (let* ((input (read-char-exclusive))
1864            (choice (assoc
1865                     (char-to-string input) org-ref-cite-menu-funcs)))
1866       ;; now run the function (2nd element in choice)
1867       (when choice
1868         (funcall
1869          (elt
1870           choice
1871           2))))))
1872
1873 ;; *** Generation of the cite links
1874 (defmacro org-ref-make-completion-function (type)
1875   "Macro to make a link completion function for a link of TYPE."
1876   `(defun ,(intern (format "org-%s-complete-link" type)) (&optional arg)
1877      (interactive)
1878      (format "%s:%s"
1879              ,type
1880              (completing-read
1881               "bibtex key: "
1882               (let ((bibtex-files (org-ref-find-bibliography)))
1883                 (bibtex-global-key-alist))))))
1884
1885 (defmacro org-ref-make-format-function (type)
1886   "Macro to make a format function for a link of TYPE."
1887   `(defun ,(intern (format "org-ref-format-%s" type)) (keyword desc format)
1888      (cond
1889       ((eq format 'org)
1890        (mapconcat
1891         (lambda (key)
1892           (format "[[#%s][%s]]" key key))
1893         (org-ref-split-and-strip-string keyword) ","))
1894
1895       ((eq format 'ascii)
1896        (concat "["
1897                (mapconcat
1898                 (lambda (key)
1899                   (format "%s" key))
1900                 (org-ref-split-and-strip-string keyword) ",") "]"))
1901
1902       ((eq format 'html)
1903        (mapconcat
1904         (lambda (key)
1905           (format "<a href=\"#%s\">%s</a>" key key))
1906         (org-ref-split-and-strip-string keyword) ","))
1907
1908       ((eq format 'latex)
1909        (if (string= (substring type -1) "s")
1910            ;; biblatex format for multicite commands, which all end in s. These are formated as \cites{key1}{key2}...
1911            (concat "\\" ,type (mapconcat (lambda (key) (format "{%s}"  key))
1912                                          (org-ref-split-and-strip-string keyword) ""))
1913          ;; bibtex format
1914        (concat "\\" ,type (when desc (org-ref-format-citation-description desc)) "{"
1915                (mapconcat (lambda (key) key) (org-ref-split-and-strip-string keyword) ",")
1916                "}")))
1917       ;; for markdown we generate pandoc citations
1918       ((eq format 'md)
1919        (cond
1920         (desc  ;; pre and or post text
1921          (let* ((text (split-string desc "::"))
1922                 (pre (car text))
1923                 (post (cadr text)))
1924            (concat
1925             (format "[@%s," keyword)
1926             (when pre (format " %s" pre))
1927             (when post (format ", %s" post))
1928             "]")))
1929         (t
1930          (format "[%s]"
1931                  (mapconcat
1932                   (lambda (key) (concat "@" key))
1933                   (org-ref-split-and-strip-string keyword)
1934                   "; "))))))))
1935
1936 (defun org-ref-format-citation-description (desc)
1937   "Return formatted citation description.
1938 If the cite link has a DESC (description), it is optional text
1939 for the citation command.  You can specify pre and post text by
1940 separating these with ::, for example [[cite:key][pre text::post
1941 text]]."
1942   (cond
1943    ((string-match "::" desc)
1944     (format "[%s][%s]" (car (setq results (split-string desc "::"))) (cadr results)))
1945    (t (format "[%s]" desc))))
1946
1947 (defun org-ref-define-citation-link (type &optional key)
1948   "Add a citation link of TYPE for org-ref.
1949 With optional KEY, set the reftex binding. For example:
1950 \(org-ref-define-citation-link \"citez\" ?z) will create a new
1951 citez link, with reftex key of z, and the completion function."
1952   (interactive "sCitation Type: \ncKey: ")
1953
1954   ;; create the formatting function
1955   (eval `(org-ref-make-format-function ,type))
1956
1957   (eval-expression
1958    `(org-add-link-type
1959      ,type
1960      org-ref-cite-onclick-function
1961      (quote ,(intern (format "org-ref-format-%s" type)))))
1962
1963   ;; create the completion function
1964   (eval `(org-ref-make-completion-function ,type))
1965
1966   ;; store new type so it works with adding citations, which checks
1967   ;; for existence in this list
1968   (add-to-list 'org-ref-cite-types type)
1969
1970   ;; and finally if a key is specified, we modify the reftex menu
1971   (when key
1972     (setf (nth 2 (assoc 'org reftex-cite-format-builtin))
1973           (append (nth 2 (assoc 'org reftex-cite-format-builtin))
1974                   `((,key  . ,(concat type ":%l")))))))
1975
1976 ;; create all the link types and their completion functions
1977 (mapcar 'org-ref-define-citation-link org-ref-cite-types)
1978
1979 (defun org-ref-insert-cite-link (alternative-cite)
1980   "Insert a default citation link using reftex.
1981 If you are on a link, it appends to the end of the link,
1982 otherwise, a new link is inserted.  Use a prefix
1983 arg (ALTERNATIVE-CITE) to get a menu of citation types."
1984   (interactive "P")
1985   (org-ref-find-bibliography)
1986   (let* ((object (org-element-context))
1987          (link-string-beginning (org-element-property :begin object))
1988          (link-string-end (org-element-property :end object))
1989          (path (org-element-property :path object)))
1990
1991     (if (not alternative-cite)
1992
1993         (cond
1994          ;; case where we are in a link
1995          ((and (equal (org-element-type object) 'link)
1996                (-contains? org-ref-cite-types (org-element-property :type object)))
1997           (goto-char link-string-end)
1998           ;; sometimes there are spaces at the end of the link
1999           ;; this code moves point pack until no spaces are there
2000           (while (looking-back " ") (backward-char))
2001           (insert (concat "," (mapconcat 'identity (reftex-citation t ?a) ","))))
2002
2003          ;; We are next to a link, and we want to append
2004          ((save-excursion
2005             (backward-char)
2006             (and (equal (org-element-type (org-element-context)) 'link)
2007                  (-contains? org-ref-cite-types (org-element-property :type (org-element-context)))))
2008           (while (looking-back " ") (backward-char))
2009           (insert (concat "," (mapconcat 'identity (reftex-citation t ?a) ","))))
2010
2011          ;; insert fresh link
2012          (t
2013           (insert
2014            (concat org-ref-default-citation-link
2015                    ":"
2016                    (mapconcat 'identity (reftex-citation t) ",")))))
2017
2018       ;; you pressed a C-u so we run this code
2019       (reftex-citation))))
2020
2021 (defun org-ref-insert-cite-with-completion (type)
2022   "Insert a cite link of TYPE with completion."
2023   (interactive (list (ido-completing-read "Type: " org-ref-cite-types)))
2024   (insert (funcall (intern (format "org-%s-complete-link" type)))))
2025
2026 (defun org-ref-store-bibtex-entry-link ()
2027   "Save a citation link to the current bibtex entry.  Save in the default link type."
2028   (interactive)
2029   (let ((link (concat org-ref-default-citation-link
2030                  ":"
2031                  (save-excursion
2032                    (bibtex-beginning-of-entry)
2033                    (reftex-get-bib-field "=key=" (bibtex-parse-entry))))))
2034     (message "saved %s" link)
2035     (push (list link) org-stored-links)
2036     (car org-stored-links)))
2037
2038 ;; ** Index link
2039 (org-add-link-type
2040  "index"
2041  (lambda (path)
2042    (occur path))
2043
2044  (lambda (path desc format)
2045    (cond
2046     ((eq format 'latex)
2047       (format "\\index{%s}" path)))))
2048
2049 ;; this will generate a temporary index of entries in the file.
2050 (org-add-link-type
2051  "printindex"
2052  (lambda (path)
2053    (let ((*index-links* '())
2054          (*initial-letters* '()))
2055
2056      ;; get links
2057      (org-element-map (org-element-parse-buffer) 'link
2058        (lambda (link)
2059          (let ((type (nth 0 link))
2060                (plist (nth 1 link)))
2061
2062            (when (equal (plist-get plist ':type) "index")
2063              (add-to-list
2064               '*index-links*
2065               (cons (plist-get plist :path)
2066                     (format
2067                      "[[elisp:(progn (switch-to-buffer \"%s\") (goto-char %s))][%s]]"
2068 (current-buffer)
2069                      (plist-get plist :begin)  ;; position of link
2070                      ;; grab a description
2071                      (save-excursion
2072                        (goto-char (plist-get plist :begin))
2073                        (if (thing-at-point 'sentence)
2074                            ;; get a sentence
2075                            (replace-regexp-in-string
2076                             "\n" "" (thing-at-point 'sentence))
2077                          ;; or call it a link
2078                          "link")))))))))
2079
2080      ;; sort the links
2081      (setq *index-links*  (cl-sort *index-links* 'string-lessp :key 'car))
2082
2083      ;; now first letters
2084      (dolist (link *index-links*)
2085        (add-to-list '*initial-letters* (substring (car link) 0 1) t))
2086
2087      ;; now create the index
2088      (switch-to-buffer (get-buffer-create "*index*"))
2089      (org-mode)
2090      (erase-buffer)
2091      (insert "#+TITLE: Index\n\n")
2092      (dolist (letter *initial-letters*)
2093        (insert (format "* %s\n" (upcase letter)))
2094        ;; now process the links
2095        (while (and
2096                *index-links*
2097                (string= letter (substring (car (car *index-links*)) 0 1)))
2098          (let ((link (pop *index-links*)))
2099            (insert (format "%s %s\n\n" (car link) (cdr link))))))
2100      (switch-to-buffer "*index*")))
2101  ;; formatting
2102  (lambda (path desc format)
2103    (cond
2104     ((eq format 'latex)
2105       (format "\\printindex")))))
2106
2107 ;; ** Glossary link
2108 (org-add-link-type
2109  "newglossaryentry"
2110  nil ;; no follow action
2111  (lambda (path desc format)
2112    (cond
2113     ((eq format 'latex)
2114      (format "\\newglossaryentry{%s}{%s}" path desc)))))
2115
2116
2117 ;; link to entry
2118 (org-add-link-type
2119  "gls"
2120   nil ;; no follow action
2121  (lambda (path desc format)
2122    (cond
2123     ((eq format 'latex)
2124      (format "\\gls{%s}" path)))))
2125
2126 ;; plural
2127 (org-add-link-type
2128  "glspl"
2129   nil ;; no follow action
2130  (lambda (path desc format)
2131    (cond
2132     ((eq format 'latex)
2133      (format "\\glspl{%s}" path)))))
2134
2135 ;; capitalized link
2136 (org-add-link-type
2137  "Gls"
2138   nil ;; no follow action
2139  (lambda (path desc format)
2140    (cond
2141     ((eq format 'latex)
2142      (format "\\Gls{%s}" path)))))
2143
2144 ;; capitalized link
2145 (org-add-link-type
2146  "Glspl"
2147   nil ;; no follow action
2148  (lambda (path desc format)
2149    (cond
2150     ((eq format 'latex)
2151      (format "\\Glspl{%s}" path)))))
2152
2153 ;; * Utilities
2154 ;; ** create text citations from a bibtex entry
2155 (defun org-ref-bib-citation ()
2156   "From a bibtex entry, create and return a simple citation string.
2157 This assumes you are in an article."
2158   (bibtex-set-dialect nil t)
2159   (bibtex-beginning-of-entry)
2160   (let* ((cb (current-buffer))
2161          (bibtex-expand-strings t)
2162          (entry (cl-loop for (key . value) in (bibtex-parse-entry t)
2163                          collect (cons (downcase key) value)))
2164          (title (replace-regexp-in-string "\n\\|\t\\|\s+" " " (reftex-get-bib-field "title" entry)))
2165          (year  (reftex-get-bib-field "year" entry))
2166          (author (replace-regexp-in-string "\n\\|\t\\|\s+" " " (reftex-get-bib-field "author" entry)))
2167          (key (reftex-get-bib-field "=key=" entry))
2168          (journal (let ((jt (reftex-get-bib-field "journal" entry)))
2169                     (if (string= "" jt)
2170                         (reftex-get-bib-field "journaltitle" entry)
2171                       jt)))
2172          (volume (reftex-get-bib-field "volume" entry))
2173          (pages (reftex-get-bib-field "pages" entry))
2174          (doi (reftex-get-bib-field "doi" entry))
2175          (url (reftex-get-bib-field "url" entry))
2176          )
2177     ;;authors, "title", Journal, vol(iss):pages (year).
2178     (format "%s, \"%s\", %s, %s:%s (%s)"
2179             author title journal  volume pages year)))
2180
2181 (defun org-ref-bib-html-citation ()
2182   "From a bibtex entry, create and return a simple citation with html links."
2183   (bibtex-beginning-of-entry)
2184   (let* ((cb (current-buffer))
2185          (bibtex-expand-strings t)
2186          (entry (cl-loop for (key . value) in (bibtex-parse-entry t)
2187                          collect (cons (downcase key) value)))
2188          (title (replace-regexp-in-string "\n\\|\t\\|\s+" " " (reftex-get-bib-field "title" entry)))
2189          (year  (reftex-get-bib-field "year" entry))
2190          (author (replace-regexp-in-string "\n\\|\t\\|\s+" " " (reftex-get-bib-field "author" entry)))
2191          (key (reftex-get-bib-field "=key=" entry))
2192          (journal (reftex-get-bib-field "journal" entry))
2193          (volume (reftex-get-bib-field "volume" entry))
2194          (pages (reftex-get-bib-field "pages" entry))
2195          (doi (reftex-get-bib-field "doi" entry))
2196          (url (reftex-get-bib-field "url" entry)))
2197     ;;authors, "title", Journal, vol(iss):pages (year).
2198     (concat (format "%s, \"%s\", %s, %s:%s (%s)."
2199                     author title journal  volume pages year)
2200             (when url (format " <a href=\"%s\">link</a>" url))
2201             (when doi
2202               (format " <a href=\"http://dx.doi.org/%s\">doi</a>" doi)))))
2203
2204 ;; ** Open pdf in bibtex entry
2205 (defun org-ref-open-bibtex-pdf ()
2206   "Open pdf for a bibtex entry, if it exists.
2207 assumes point is in
2208 the entry of interest in the bibfile.  but does not check that."
2209   (interactive)
2210   (save-excursion
2211     (bibtex-beginning-of-entry)
2212     (let* ((bibtex-expand-strings t)
2213            (entry (bibtex-parse-entry t))
2214            (key (reftex-get-bib-field "=key=" entry))
2215            (pdf (format (concat org-ref-pdf-directory "%s.pdf") key)))
2216       (message "%s" pdf)
2217       (if (file-exists-p pdf)
2218           (org-open-link-from-string (format "[[file:%s]]" pdf))
2219         (ding)))))
2220
2221 ;; ** Open notes from bibtex entry
2222
2223 (defun org-ref-open-bibtex-notes ()
2224   "From a bibtex entry, open the notes if they exist, and create a heading if they do not.
2225
2226 I never did figure out how to use reftex to make this happen
2227 non-interactively. the reftex-format-citation function did not
2228 work perfectly; there were carriage returns in the strings, and
2229 it did not put the key where it needed to be. so, below I replace
2230 the carriage returns and extra spaces with a single space and
2231 construct the heading by hand."
2232   (interactive)
2233
2234   (bibtex-beginning-of-entry)
2235   (let* ((cb (current-buffer))
2236          (bibtex-expand-strings t)
2237          (entry (cl-loop for (key . value) in (bibtex-parse-entry t)
2238                          collect (cons (downcase key) value)))
2239          (key (reftex-get-bib-field "=key=" entry)))
2240
2241     ;; save key to clipboard to make saving pdf later easier by pasting.
2242     (with-temp-buffer
2243       (insert key)
2244       (kill-ring-save (point-min) (point-max)))
2245
2246     ;; now look for entry in the notes file
2247     (if  org-ref-bibliography-notes
2248         (find-file-other-window org-ref-bibliography-notes)
2249       (error "Org-ref-bib-bibliography-notes is not set to anything"))
2250
2251     (goto-char (point-min))
2252     ;; put new entry in notes if we don't find it.
2253     (if (re-search-forward (format ":Custom_ID: %s$" key) nil 'end)
2254         (funcall org-ref-open-notes-function)
2255       ;; no entry found, so add one
2256       (insert (org-ref-reftex-format-citation entry (concat "\n" org-ref-note-title-format)))
2257       (insert (org-ref-reftex-format-citation
2258                entry
2259                (concat "
2260  :PROPERTIES:
2261   :Custom_ID: %k
2262   :AUTHOR: %9a
2263   :JOURNAL: %j
2264   :YEAR: %y
2265   :VOLUME: %v
2266   :PAGES: %p
2267   :DOI: %D
2268   :URL: %U
2269  :END:
2270 "
2271                        (format "[[cite:%s]] [[file:%s/%s.pdf][pdf]]\n\n"
2272                                key org-ref-pdf-directory key))))
2273       (save-buffer))))
2274
2275 (defun org-ref-open-notes-from-reftex ()
2276   "Call reftex, and open notes for selected entry."
2277   (interactive)
2278   (let ((bibtex-key )))
2279
2280   ;; now look for entry in the notes file
2281   (if  org-ref-bibliography-notes
2282       (find-file-other-window org-ref-bibliography-notes)
2283     (error "Org-ref-bib-bibliography-notes is not set to anything"))
2284
2285   (goto-char (point-min))
2286
2287   (re-search-forward (format
2288                       ":Custom_ID: %s$"
2289                       (cl-first (reftex-citation t)) nil 'end))
2290   (funcall org-ref-open-notes-function))
2291
2292 ;; ** Open bibtex entry in browser
2293 (defun org-ref-open-in-browser ()
2294   "Open the bibtex entry at point in a browser using the url field or doi field."
2295 (interactive)
2296 (save-excursion
2297   (bibtex-beginning-of-entry)
2298   (catch 'done
2299     (let ((url (bibtex-autokey-get-field "url")))
2300       (when  url
2301         (browse-url url)
2302         (throw 'done nil)))
2303
2304     (let ((doi (bibtex-autokey-get-field "doi")))
2305       (when doi
2306         (if (string-match "^http" doi)
2307             (browse-url doi)
2308           (browse-url (format "http://dx.doi.org/%s" doi)))
2309         (throw 'done nil)))
2310     (message "No url or doi found"))))
2311
2312 ;; ** upload entry to citeulike
2313
2314 (defun org-ref-upload-bibtex-entry-to-citeulike ()
2315   "With point in  a bibtex entry get bibtex string and submit to citeulike.
2316
2317 Relies on the python script /upload_bibtex_citeulike.py being in the user directory."
2318   (interactive)
2319   (message "uploading to citeulike")
2320   (save-restriction
2321     (bibtex-narrow-to-entry)
2322     (let ((startpos (point-min))
2323           (endpos (point-max))
2324           (bibtex-string (buffer-string))
2325           (script (concat "python " starter-kit-dir "/upload_bibtex_citeulike.py&")))
2326       (with-temp-buffer (insert bibtex-string)
2327                         (shell-command-on-region (point-min) (point-max) script t nil nil t)))))
2328
2329 ;; ** Build a pdf of the bibtex file
2330 (defun org-ref-build-full-bibliography ()
2331   "Build pdf of all bibtex entries, and open it."
2332   (interactive)
2333   (let* ((bibfile (file-name-nondirectory (buffer-file-name)))
2334         (bib-base (file-name-sans-extension bibfile))
2335         (texfile (concat bib-base ".tex"))
2336         (pdffile (concat bib-base ".pdf")))
2337     (find-file texfile)
2338     (erase-buffer)
2339     (insert (format "\\documentclass[12pt]{article}
2340 \\usepackage[version=3]{mhchem}
2341 \\usepackage{url}
2342 \\usepackage[numbers]{natbib}
2343 \\usepackage[colorlinks=true, linkcolor=blue, urlcolor=blue, pdfstartview=FitH]{hyperref}
2344 \\usepackage{doi}
2345 \\begin{document}
2346 \\nocite{*}
2347 \\bibliographystyle{unsrtnat}
2348 \\bibliography{%s}
2349 \\end{document}" bib-base))
2350     (save-buffer)
2351     (shell-command (concat "pdflatex " bib-base))
2352     (shell-command (concat "bibtex " bib-base))
2353     (shell-command (concat "pdflatex " bib-base))
2354     (shell-command (concat "pdflatex " bib-base))
2355     (kill-buffer texfile)
2356     (org-open-file pdffile)
2357     ))
2358
2359 ;; ** Extract bibtex entries in org-file
2360
2361 (defun org-ref-extract-bibtex-entries ()
2362   "Extract the bibtex entries referred to by cite links in the current buffer into a src block at the bottom of the current buffer.
2363
2364 If no bibliography is in the buffer the variable
2365 `reftex-default-bibliography' is used."
2366   (interactive)
2367   (let* ((temporary-file-directory (file-name-directory (buffer-file-name)))
2368          (tempname (make-temp-file "extract-bib"))
2369          (contents (buffer-string))
2370          (cb (current-buffer))
2371          basename texfile bibfile results)
2372
2373     ;; open tempfile and insert org-buffer contents
2374     (find-file tempname)
2375     (insert contents)
2376     (setq basename (file-name-sans-extension
2377                     (file-name-nondirectory buffer-file-name))
2378           texfile (concat tempname ".tex")
2379           bibfile (concat tempname ".bib"))
2380
2381     ;; see if we have a bibliography, and insert the default one if not.
2382     (save-excursion
2383       (goto-char (point-min))
2384       (unless (re-search-forward "^bibliography:" (point-max) 'end)
2385         (insert (format "\nbibliography:%s"
2386                         (mapconcat 'identity reftex-default-bibliography ",")))))
2387     (save-buffer)
2388
2389     ;; get a latex file and extract the references
2390     (org-latex-export-to-latex)
2391     (find-file texfile)
2392     (reftex-parse-all)
2393     (reftex-create-bibtex-file bibfile)
2394     (save-buffer)
2395     ;; save results of the references
2396     (setq results (buffer-string))
2397
2398     ;; kill buffers. these are named by basename, not full path
2399     (kill-buffer (concat basename ".bib"))
2400     (kill-buffer (concat basename ".tex"))
2401     (kill-buffer basename)
2402
2403     (delete-file bibfile)
2404     (delete-file texfile)
2405     (delete-file tempname)
2406
2407     ;; Now back to the original org buffer and insert the results
2408     (switch-to-buffer cb)
2409     (when (not (string= "" results))
2410       (save-excursion
2411         (goto-char (point-max))
2412         (insert "\n\n")
2413         (org-insert-heading)
2414         (insert (format " Bibtex entries
2415
2416 #+BEGIN_SRC text :tangle %s
2417 %s
2418 #+END_SRC" (concat (file-name-sans-extension (file-name-nondirectory (buffer-file-name))) ".bib") results))))))
2419
2420 ;; ** Find bad citations
2421 (require 'cl)
2422
2423 (defun index (substring list)
2424   "Return the index of SUBSTRING in a LIST of strings."
2425   (let ((i 0)
2426         (found nil))
2427     (dolist (arg list i)
2428       (if (string-match (concat "^" substring "$") arg)
2429           (progn
2430             (setq found t)
2431             (return i)))
2432       (setq i (+ i 1)))
2433     ;; return counter if found, otherwise return nil
2434     (if found i nil)))
2435
2436
2437 (defun org-ref-find-bad-citations ()
2438   "Create a list of citation keys in an org-file that do not have a bibtex entry in the known bibtex files.
2439
2440 Makes a new buffer with clickable links."
2441   (interactive)
2442   ;; generate the list of bibtex-keys and cited keys
2443   (let* ((bibtex-files (org-ref-find-bibliography))
2444          (bibtex-file-path (mapconcat (lambda (x) (file-name-directory (file-truename x))) bibtex-files ":"))
2445          (bibtex-keys (mapcar (lambda (x) (car x)) (bibtex-global-key-alist)))
2446          (bad-citations '()))
2447
2448     (org-element-map (org-element-parse-buffer) 'link
2449       (lambda (link)
2450         (let ((plist (nth 1 link)))
2451           (when (-contains? org-ref-cite-types (plist-get plist :type))
2452             (dolist (key (org-ref-split-and-strip-string (plist-get plist :path)))
2453               (when (not (index key bibtex-keys))
2454                 (setq
2455                  bad-citations
2456                  (append
2457                   bad-citations
2458                   `(,(format "%s [[elisp:(progn (switch-to-buffer-other-frame \"%s\")(goto-char %s))][not found here]]\n"
2459                              key
2460                              (buffer-name)
2461                              (plist-get plist :begin)))))
2462                 )))))
2463       ;; set with-affilates to t to get citations in a caption
2464       nil nil nil t)
2465
2466     (if bad-citations
2467       (progn
2468         (switch-to-buffer-other-window "*Missing citations*")
2469         (org-mode)
2470         (erase-buffer)
2471         (insert "* List of bad cite links\n")
2472         (insert (mapconcat 'identity bad-citations ""))
2473                                         ;(setq buffer-read-only t)
2474         (use-local-map (copy-keymap org-mode-map))
2475         (local-set-key "q" #'(lambda () (interactive) (kill-buffer))))
2476
2477       (when (get-buffer "*Missing citations*")
2478           (kill-buffer "*Missing citations*"))
2479       (message "No bad cite links found"))))
2480
2481 ;; ** helm interface to bad citations, labels, refs and files in orgfile
2482 (defun org-ref-bad-cite-candidates ()
2483   "Return a list of conses (key . marker) where key does not exist in the known bibliography files, and marker points to the key."
2484   (let* ((cp (point))                   ; save to return to later
2485          (bibtex-files (org-ref-find-bibliography))
2486          (bibtex-file-path (mapconcat
2487                             (lambda (x)
2488                               (file-name-directory (file-truename x)))
2489                             bibtex-files ":"))
2490          (bibtex-keys (mapcar (lambda (x) (car x))
2491                               (bibtex-global-key-alist)))
2492          (bad-citations '()))
2493
2494     (org-element-map (org-element-parse-buffer) 'link
2495       (lambda (link)
2496         (let ((plist (nth 1 link)))
2497           (when (-contains? org-ref-cite-types (plist-get plist :type))
2498             (dolist (key (org-ref-split-and-strip-string (plist-get plist :path)) )
2499               (when (not (index key bibtex-keys))
2500                 (goto-char (plist-get plist :begin))
2501                 (re-search-forward key)
2502                 (push (cons key (point-marker)) bad-citations)))
2503             )))
2504       ;; add with-affiliates to get cites in caption
2505       nil nil nil t)
2506     (goto-char cp)
2507     bad-citations))
2508
2509
2510 (defun org-ref-bad-ref-candidates ()
2511   "Return a list of conses (ref . marker) where ref is a ref link that does not point to anything (i.e. a label)."
2512   ;; first get a list of legitimate labels
2513   (let ((cp (point))
2514         (labels (org-ref-get-labels))
2515         (bad-refs '()))
2516     ;; now loop over ref links
2517     (goto-char (point-min))
2518     (org-element-map (org-element-parse-buffer) 'link
2519       (lambda (link)
2520         (let ((plist (nth 1 link)))
2521           (when (or  (equal (plist-get plist ':type) "ref")
2522                      (equal (plist-get plist ':type) "eqref")
2523                      (equal (plist-get plist ':type) "pageref")
2524                      (equal (plist-get plist ':type) "nameref"))
2525             (unless (-contains? labels (plist-get plist :path))
2526               (goto-char (plist-get plist :begin))
2527               (add-to-list
2528                'bad-refs
2529                (cons (plist-get plist :path)
2530                      (point-marker))))))))
2531     (goto-char cp)
2532     bad-refs))
2533
2534
2535 (defun org-ref-bad-label-candidates ()
2536   "Return a list of labels where label is multiply defined."
2537   (let ((labels (org-ref-get-labels))
2538         (multiple-labels '()))
2539     (when (not (= (length labels)
2540                   (length (-uniq labels))))
2541       (dolist (label labels)
2542         (when (> (-count (lambda (a)
2543                            (equal a label))
2544                          labels) 1)
2545           ;; this is a multiply defined label.
2546           (let ((cp (point)))
2547             (goto-char (point-min))
2548             (while (re-search-forward
2549                     (format  "[^#+]label:%s\\s-" label) nil t)
2550               (push (cons label (point-marker)) multiple-labels))
2551             (goto-char (point-min))
2552             (while (re-search-forward
2553                     (format  "\\label{%s}\\s-?" label) nil t)
2554               (push (cons label (point-marker)) multiple-labels))
2555
2556             (goto-char (point-min))
2557             (while (re-search-forward
2558                     (format  "^#\\+label:\\s-*%s" label) nil t)
2559               (push (cons label (point-marker)) multiple-labels))
2560
2561             (goto-char (point-min))
2562             (while (re-search-forward
2563                     (format   "^#\\+tblname:\\s-*%s" label) nil t)
2564               (push (cons label (point-marker)) multiple-labels))
2565             (goto-char cp)))))
2566       multiple-labels))
2567
2568 (defun org-ref-bad-file-link-candidates ()
2569   "Return list of conses (link . marker) wehre the file in the link does not exist."
2570   (let* ((bad-files '()))
2571     (org-element-map (org-element-parse-buffer) 'link
2572       (lambda (link)
2573         (let ((type (org-element-property :type link)))
2574           (when (or  (string= "file" type)
2575                      (string= "attachfile" type))
2576             (unless (file-exists-p (org-element-property :path link))
2577               (add-to-list 'bad-files
2578                            (cons (org-element-property :path link)
2579                                  (save-excursion
2580                                    (goto-char
2581                                     (org-element-property :begin link))
2582                                    (point-marker)))))))))
2583     ;; Let us also check \attachfile{fname}
2584     (save-excursion
2585       (goto-char (point-min))
2586       (while (re-search-forward "\\attachfile{\\(.*\\)}" nil t)
2587         (unless (file-exists-p (match-string 1))
2588           (add-to-list 'bad-files (cons (match-string 1) (point-marker))))))
2589     bad-files))
2590
2591 ;;;###autoload
2592 (defun org-ref ()
2593   "Opens a helm interface to actions for org-ref.
2594 Shows bad citations, ref links and labels"
2595   (interactive)
2596   (let ((cb (current-buffer))
2597         (bad-citations (org-ref-bad-cite-candidates))
2598         (bad-refs (org-ref-bad-ref-candidates))
2599         (bad-labels (org-ref-bad-label-candidates))
2600         (bad-files (org-ref-bad-file-link-candidates)))
2601
2602     (helm :sources `(((name . "Bad citations")
2603                        (candidates . ,bad-citations)
2604                        (action . (lambda (marker)
2605                                    (switch-to-buffer (marker-buffer marker))
2606                                    (goto-char marker))))
2607                      ;;
2608                      ((name . "Bad Labels")
2609                       (candidates . ,bad-labels)
2610                       (action . (lambda (marker)
2611                                    (switch-to-buffer (marker-buffer marker))
2612                                    (goto-char marker))))
2613                      ;;
2614                      ((name . "Bad ref links")
2615                       (candidates . ,bad-refs)
2616                       (action . (lambda (marker)
2617                                           (switch-to-buffer (marker-buffer marker))
2618                                           (goto-char marker))))
2619                      ;;
2620                      ((name . "Bad file links")
2621                       (candidates . ,bad-files)
2622                       (lambda (marker)
2623                                    (switch-to-buffer (marker-buffer marker))
2624                                    (goto-char marker)))
2625                      ;;
2626                      ((name . "Utilities")
2627                       (candidates . (("Check buffer again" . org-ref)
2628                                      ("Insert citation" . helm-bibtex)
2629                                      ("Insert label link" . org-ref-helm-insert-label-link)
2630                                      ("Insert ref link" . org-ref-helm-insert-ref-link)
2631                                      ("List of figures" . org-ref-list-of-figures)
2632                                      ("List of tables" . org-ref-list-of-tables)
2633                                      ("Table of contents" . nil)
2634                                      ))
2635                       (action . (lambda (x)
2636                                   (switch-to-buffer ,cb)
2637                                   (funcall x))))
2638                      ;;
2639                      ((name . "Export functions")
2640                       (candidates . (("Extract cited entries" . org-ref-extract-bibtex-entries)
2641                                      ("Export to html and open" . (lambda () (org-open-file (org-html-export-to-html))))
2642                                      ("Export to pdf and open" . (lambda ()
2643                                                                    (org-open-file (org-latex-export-to-pdf))))
2644                                      ("Export to manuscript pdf and open" . ox-manuscript-export-and-build-and-open)
2645                                      ("Export submission manuscript pdf and open" . ox-manuscript-build-submission-manuscript-and-open)
2646
2647                                      ))
2648                       (action . (lambda (x)
2649                                   (switch-to-buffer ,cb)
2650                                   (funcall x))))))))
2651
2652 ;; ** Find non-ascii charaters
2653 (defun org-ref-find-non-ascii-characters ()
2654   "Find non-ascii characters in the buffer.  Useful for cleaning up bibtex files."
2655   (interactive)
2656   (occur "[^[:ascii:]]"))
2657
2658 ;; ** Sort fields in a bibtex entry
2659
2660 (defun org-ref-sort-bibtex-entry ()
2661   "Sort fields of entry in standard order and downcase them."
2662   (interactive)
2663   (bibtex-beginning-of-entry)
2664   (let* ((master '("author" "title" "journal" "volume" "number" "pages" "year" "doi" "url"))
2665          (entry (bibtex-parse-entry))
2666          (entry-fields)
2667          (other-fields)
2668          (type (cdr (assoc "=type=" entry)))
2669          (key (cdr (assoc "=key=" entry))))
2670
2671     ;; these are the fields we want to order that are in this entry
2672     (setq entry-fields (mapcar (lambda (x) (car x)) entry))
2673     ;; we do not want to reenter these fields
2674     (setq entry-fields (remove "=key=" entry-fields))
2675     (setq entry-fields (remove "=type=" entry-fields))
2676
2677     ;;these are the other fields in the entry
2678     (setq other-fields (remove-if-not (lambda(x) (not (member x master))) entry-fields))
2679
2680     (cond
2681      ;; right now we only resort articles
2682      ((string= (downcase type) "article")
2683       (bibtex-kill-entry)
2684       (insert
2685        (concat "@article{" key ",\n"
2686                (mapconcat
2687                 (lambda (field)
2688                   (when (member field entry-fields)
2689                     (format "%s = %s," (downcase field) (cdr (assoc field entry))))) master "\n")
2690                (mapconcat
2691                 (lambda (field)
2692                   (format "%s = %s," (downcase field) (cdr (assoc field entry)))) other-fields "\n")
2693                "\n}\n\n"))
2694       (bibtex-find-entry key)
2695       (bibtex-fill-entry)
2696       (bibtex-clean-entry)
2697        ))))
2698
2699 ;; ** Clean a bibtex entry
2700 (defun org-ref-clean-bibtex-entry(&optional keep-key)
2701   "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"
2702   (interactive "P")
2703   (bibtex-beginning-of-entry)
2704 (end-of-line)
2705   ;; some entries do not have a key or comma in first line. We check and add it, if needed.
2706   (unless (string-match ",$" (thing-at-point 'line))
2707     (end-of-line)
2708     (insert ","))
2709
2710   ;; check for empty pages, and put eid or article id in its place
2711   (let ((entry (bibtex-parse-entry))
2712         (pages (bibtex-autokey-get-field "pages"))
2713         (year (bibtex-autokey-get-field "year"))
2714         (doi  (bibtex-autokey-get-field "doi"))
2715         ;; The Journal of Chemical Physics uses eid
2716         (eid (bibtex-autokey-get-field "eid")))
2717
2718     ;; replace http://dx.doi.org/ in doi. some journals put that in,
2719     ;; but we only want the doi.
2720     (when (string-match "^http://dx.doi.org/" doi)
2721       (bibtex-beginning-of-entry)
2722       (goto-char (car (cdr (bibtex-search-forward-field "doi" t))))
2723       (bibtex-kill-field)
2724       (bibtex-make-field "doi")
2725       (backward-char)
2726       (insert (replace-regexp-in-string "^http://dx.doi.org/" "" doi)))
2727
2728     ;; asap articles often set year to 0, which messes up key
2729     ;; generation. fix that.
2730     (when (string= "0" year)
2731       (bibtex-beginning-of-entry)
2732       (goto-char (car (cdr (bibtex-search-forward-field "year" t))))
2733       (bibtex-kill-field)
2734       (bibtex-make-field "year")
2735       (backward-char)
2736       (insert (read-string "Enter year: ")))
2737
2738     ;; fix pages if they are empty if there is an eid to put there.
2739     (when (string= "-" pages)
2740       (when eid
2741         (bibtex-beginning-of-entry)
2742         ;; this seems like a clunky way to set the pages field.But I
2743         ;; cannot find a better way.
2744         (goto-char (car (cdr (bibtex-search-forward-field "pages" t))))
2745         (bibtex-kill-field)
2746         (bibtex-make-field "pages")
2747         (backward-char)
2748         (insert eid)))
2749
2750     ;; replace naked & with \&
2751     (save-restriction
2752       (bibtex-narrow-to-entry)
2753       (bibtex-beginning-of-entry)
2754       (message "checking &")
2755       (replace-regexp " & " " \\\\& ")
2756       (widen))
2757
2758     ;; generate a key, and if it duplicates an existing key, edit it.
2759     (unless keep-key
2760       (let ((key (bibtex-generate-autokey)))
2761
2762         ;; first we delete the existing key
2763         (bibtex-beginning-of-entry)
2764         (re-search-forward bibtex-entry-maybe-empty-head)
2765         (if (match-beginning bibtex-key-in-head)
2766             (delete-region (match-beginning bibtex-key-in-head)
2767                            (match-end bibtex-key-in-head)))
2768         ;; check if the key is in the buffer
2769         (when (save-excursion
2770                 (bibtex-search-entry key))
2771           (save-excursion
2772             (bibtex-search-entry key)
2773             (bibtex-copy-entry-as-kill)
2774             (switch-to-buffer-other-window "*duplicate entry*")
2775             (bibtex-yank))
2776           (setq key (bibtex-read-key "Duplicate Key found, edit: " key)))
2777
2778         (insert key)
2779         (kill-new key))) ;; save key for pasting
2780
2781     ;; run hooks. each of these operates on the entry with no arguments.
2782     ;; this did not work like  i thought, it gives a symbolp error.
2783     ;; (run-hooks org-ref-clean-bibtex-entry-hook)
2784     (mapcar (lambda (x)
2785               (save-restriction
2786                 (save-excursion
2787                   (funcall x))))
2788             org-ref-clean-bibtex-entry-hook)
2789
2790     ;; sort fields within entry
2791     (org-ref-sort-bibtex-entry)
2792     ;; check for non-ascii characters
2793     (occur "[^[:ascii:]]")
2794     ))
2795
2796 (defun org-ref-get-citation-year (key)
2797   "Get the year of an entry with KEY.  Return year as a string."
2798   (let* ((results (org-ref-get-bibtex-key-and-file key))
2799          (bibfile (cdr results)))
2800     (with-temp-buffer
2801       (insert-file-contents bibfile)
2802       (bibtex-set-dialect (parsebib-find-bibtex-dialect) t)
2803       (bibtex-search-entry key nil 0)
2804       (prog1 (reftex-get-bib-field "year" (bibtex-parse-entry t))
2805         ))))
2806
2807 ;; ** Sort cite in cite link
2808 (defun org-ref-sort-citation-link ()
2809  "Replace link at point with sorted link by year."
2810  (interactive)
2811  (let* ((object (org-element-context))
2812         (type (org-element-property :type object))
2813         (begin (org-element-property :begin object))
2814         (end (org-element-property :end object))
2815         (link-string (org-element-property :path object))
2816         keys years data)
2817   (setq keys (org-ref-split-and-strip-string link-string))
2818   (setq years (mapcar 'org-ref-get-citation-year keys))
2819   (setq data (mapcar* (lambda (a b) `(,a . ,b)) years keys))
2820   (setq data (cl-sort data (lambda (x y) (< (string-to-number (car x)) (string-to-number (car y))))))
2821   ;; now get the keys separated by commas
2822   (setq keys (mapconcat (lambda (x) (cdr x)) data ","))
2823   ;; and replace the link with the sorted keys
2824   (cl--set-buffer-substring begin end (concat type ":" keys))))
2825
2826 ;; ** Shift-arrow sorting of keys in a cite link
2827
2828 (defun org-ref-swap-keys (i j keys)
2829  "Swap the KEYS in a list with index I and J."
2830  (let ((tempi (nth i keys)))
2831    (setf (nth i keys) (nth j keys))
2832    (setf (nth j keys) tempi))
2833   keys)
2834
2835
2836 (defun org-ref-swap-citation-link (direction)
2837  "Move citation at point in DIRECTION +1 is to the right, -1 to the left."
2838  (interactive)
2839  (let* ((object (org-element-context))
2840         (type (org-element-property :type object))
2841         (begin (org-element-property :begin object))
2842         (end (org-element-property :end object))
2843         (link-string (org-element-property :path object))
2844         key keys i)
2845    ;;   We only want this to work on citation links
2846    (when (-contains? org-ref-cite-types type)
2847         (setq key (org-ref-get-bibtex-key-under-cursor))
2848         (setq keys (org-ref-split-and-strip-string link-string))
2849         (setq i (index key keys))  ;; defined in org-ref
2850         (if (> direction 0) ;; shift right
2851             (org-ref-swap-keys i (+ i 1) keys)
2852           (org-ref-swap-keys i (- i 1) keys))
2853         (setq keys (mapconcat 'identity keys ","))
2854         ;; and replace the link with the sorted keys
2855         (cl--set-buffer-substring
2856          begin end
2857          (concat
2858           type ":" keys
2859           ;; It seems the space at the end can get consumed, so we see if there
2860           ;; is a space, and add it if so. Sometimes there is a comma or period,
2861           ;; then we do not want a space.
2862           (when
2863               (save-excursion
2864                 (goto-char end)
2865                 (looking-back " ")) " ")))
2866         ;; now go forward to key so we can move with the key
2867         (re-search-forward key)
2868         (goto-char (match-beginning 0)))))
2869
2870 ;; add hooks to make it work
2871 (add-hook 'org-shiftright-hook (lambda () (org-ref-swap-citation-link 1)))
2872 (add-hook 'org-shiftleft-hook (lambda () (org-ref-swap-citation-link -1)))
2873
2874 ;; ** context around org-ref links
2875 (defun org-ref-get-label-context (label)
2876   "Return a string of context around a LABEL."
2877   (save-excursion
2878     (catch 'result
2879       (goto-char (point-min))
2880       (when (re-search-forward
2881              (format "label:%s\\b" label) nil t)
2882         (throw 'result (buffer-substring
2883                         (progn
2884                           (previous-line)
2885                           (beginning-of-line)
2886                           (point))
2887                         (progn
2888                           (forward-line 4)
2889                           (point)))))
2890
2891       (goto-char (point-min))
2892       (when (re-search-forward
2893              (format "\\label{%s}" label) nil t)
2894         (throw 'result (buffer-substring
2895                         (progn
2896                           (previous-line)
2897                           (beginning-of-line)
2898                           (point))
2899                         (progn
2900                           (forward-line 4)
2901                           (point)))))
2902
2903       (goto-char (point-min))
2904       (when (re-search-forward
2905              (format "^#\\+label:\\s-*\\(%s\\)\\b" label) nil t)
2906         (throw 'result (buffer-substring
2907                         (progn
2908                           (previous-line)
2909                           (beginning-of-line)
2910                           (point))
2911                         (progn
2912                           (forward-line 4)
2913                           (point)))))
2914
2915       (goto-char (point-min))
2916       (when (re-search-forward
2917              (format "^#\\+tblname:\\s-*\\(%s\\)\\b" label) nil t)
2918         (throw 'result (buffer-substring
2919                         (progn
2920                           (previous-line)
2921                           (beginning-of-line)
2922                           (point))
2923                         (progn
2924                           (forward-line 4)
2925                           (point)))))
2926       (throw 'result "!!! NO CONTEXT FOUND !!!"))))
2927
2928
2929 (defun org-ref-link-message ()
2930   "Print a minibuffer message about the link that point is on."
2931   (interactive)
2932   (save-restriction
2933     (widen)
2934     (when (eq major-mode 'org-mode)
2935       (let* ((object (org-element-context))
2936              (type (org-element-property :type object)))
2937         (save-excursion
2938           (cond
2939            ;; cite links
2940            ((-contains? org-ref-cite-types type)
2941             (message (org-ref-get-citation-string-at-point)))
2942
2943            ;; message some context about the label we are referring to
2944            ((string= type "ref")
2945             (message "%scount: %s"
2946                      (org-ref-get-label-context
2947                       (org-element-property :path object))
2948                      (org-ref-count-labels
2949                       (org-element-property :path object))))
2950
2951            ((string= type "eqref")
2952             (message "%scount: %s"
2953                      (org-ref-get-label-context
2954                       (org-element-property :path object))
2955                      (org-ref-count-labels
2956                       (org-element-property :path object))))
2957
2958            ;; message the count
2959            ((string= type "label")
2960             (let ((count (org-ref-count-labels
2961                           (org-element-property :path object))))
2962               ;; get plurality on occurrence correct
2963               (message (concat
2964                         (number-to-string count)
2965                         " occurence"
2966                         (when (or (= count 0)
2967                                   (> count 1))
2968                           "s")))))
2969
2970            ((string= type "custom-id")
2971             (save-excursion
2972               (org-open-link-from-string
2973                (format "[[#%s]]" (org-element-property :path object)))
2974               (message "%s" (org-get-heading))))
2975
2976            ;; check if the bibliography files exist.
2977            ((string= type "bibliography")
2978             (let* ((bibfile)
2979                    ;; object is the link you clicked on
2980                    (object (org-element-context))
2981                    (link-string (org-element-property :path object))
2982                    (link-string-beginning)
2983                    (link-string-end))
2984               (save-excursion
2985                 (goto-char (org-element-property :begin object))
2986                 (search-forward link-string nil nil 1)
2987                 (setq link-string-beginning (match-beginning 0))
2988                 (setq link-string-end (match-end 0)))
2989
2990               ;; make sure we are in link and not before the :
2991               (when (> link-string-beginning (point))
2992                 (goto-char link-string-beginning))
2993
2994               (let (key-beginning key-end)
2995                 ;; now if we have comma separated bibliographies
2996                 ;; we find the one clicked on. we want to
2997                 ;; search forward to next comma from point
2998                 (save-excursion
2999                   (if (search-forward "," link-string-end 1 1)
3000                       (setq key-end (- (match-end 0) 1)) ; we found a match
3001                     (setq key-end (point)))) ; no comma found so take the point
3002
3003                 ;; and backward to previous comma from point
3004                 (save-excursion
3005                   (if (search-backward "," link-string-beginning 1 1)
3006                       (setq key-beginning (+ (match-beginning 0) 1)) ; we found a match
3007                     (setq key-beginning (point)))) ; no match found
3008                 ;; save the key we clicked on.
3009                 (setq bibfile
3010                       (org-ref-strip-string
3011                        (buffer-substring key-beginning key-end)))
3012                 (if (file-exists-p bibfile)
3013                     (message "%s exists." bibfile)
3014                   (message "!!! %s NOT FOUND !!!" bibfile)))))))))))
3015
3016 ;; ** aliases
3017 (defalias 'oro 'org-ref-open-citation-at-point)
3018 (defalias 'orc 'org-ref-citation-at-point)
3019 (defalias 'orp 'org-ref-open-pdf-at-point)
3020 (defalias 'oru 'org-ref-open-url-at-point)
3021 (defalias 'orn 'org-ref-open-notes-at-point)
3022 (defalias 'ornr 'org-ref-open-notes-from-reftex)
3023
3024 (defalias 'orib 'org-ref-insert-bibliography-link)
3025 (defalias 'oric 'org-ref-insert-cite-link)
3026 (defalias 'orir 'org-ref-insert-ref-link)
3027 (defalias 'orsl 'org-ref-store-bibtex-entry-link)
3028
3029 (defalias 'orcb 'org-ref-clean-bibtex-entry)
3030
3031 ;; * Helm bibtex setup
3032
3033 (setq helm-bibtex-additional-search-fields '(keywords))
3034
3035 (defun helm-bibtex-candidates-formatter (candidates source)
3036   "Formats BibTeX entries for display in results list.
3037 Argument CANDIDATES helm candidates.
3038 Argument SOURCE the helm source."
3039   (cl-loop
3040    with width = (with-helm-window (helm-bibtex-window-width))
3041    for entry in candidates
3042    for entry = (cdr entry)
3043    for entry-key = (helm-bibtex-get-value "=key=" entry)
3044    if (assoc-string "author" entry 'case-fold)
3045      for fields = '("author" "title" "year" "=has-pdf=" "=has-note=" "=type=")
3046    else
3047      for fields = '("editor" "title" "year" "=has-pdf=" "=has-note=" "=type=")
3048    for fields = (--map (helm-bibtex-clean-string
3049                         (helm-bibtex-get-value it entry " "))
3050                        fields)
3051    for fields = (-update-at 0 'helm-bibtex-shorten-authors fields)
3052    for fields = (append fields
3053                          (list  (or (helm-bibtex-get-value "keywords" entry)
3054                                     "" )))
3055    collect
3056    (cons (s-format "$0 $1 $2 $3 $4$5 $6" 'elt
3057                    (-zip-with (lambda (f w) (truncate-string-to-width f w 0 ?\s))
3058                               fields (list 36 (- width 85) 4 1 1 7 7)))
3059          entry-key)))
3060
3061 ;; * org-ref bibtex keywords
3062 ;; adapted from bibtex-utils.el
3063 ;; these are candidates for selecting keywords/tags
3064 (defun org-ref-bibtex-keywords ()
3065   "Get keywords defined in current bibtex file.
3066 These are in the keywords field, and are comma or semicolon separated."
3067   (save-excursion
3068     (goto-char (point-min))
3069     (let (keywords kstring)
3070       (while (re-search-forward "^\\s-*keywords.*{\\([^}]+\\)}" nil t)
3071         ;; TWS - remove newlines/multiple spaces:
3072         (setq kstring (replace-regexp-in-string "[ \t\n]+" " " (match-string 1)))
3073         (mapc
3074          (lambda (v)
3075            (add-to-list 'keywords v t))
3076          (split-string kstring "\\(,\\|;\\)[ \n]*\\|{\\|}" t)))
3077       keywords)))
3078
3079
3080 (defun org-ref-set-bibtex-keywords (keywords &optional arg)
3081   "Add KEYWORDS to a bibtex entry.
3082 If KEYWORDS is a list, it is converted to a comma-separated
3083 string.  The KEYWORDS are added to the beginning of the
3084 field.  Otherwise KEYWORDS should be a string of comma-separate
3085 keywords.  Optional argument ARG prefix arg to replace keywords."
3086   (interactive "sKeywords: \nP")
3087   (bibtex-set-field
3088    "keywords"
3089    (if arg
3090        ;; replace with arg
3091        (if (listp keywords)
3092            (mapconcat 'identity keywords ", ")
3093          keywords)
3094      ;; else concatentate
3095      (concat
3096       (if (listp keywords)
3097           (mapconcat 'identity keywords ", ")
3098         keywords)
3099       (when (not (string= "" (bibtex-autokey-get-field "keywords")))
3100         (concat ", "  (bibtex-autokey-get-field "keywords"))))))
3101   (save-buffer))
3102
3103
3104 (defun helm-tag-bibtex-entry ()
3105   "Helm interface to add keywords to a bibtex entry.
3106 Run this with the point in a bibtex entry."
3107   (interactive)
3108   (let ((keyword-source `((name . "Existing keywords")
3109                           (candidates . ,(org-ref-bibtex-keywords))
3110                           (action . (lambda (candidate)
3111                                       (org-ref-set-bibtex-keywords
3112                                        (mapconcat
3113                                         'identity
3114                                         (helm-marked-candidates)
3115                                         ", "))))))
3116         (fallback-source `((name . "Add new keywords")
3117                            (dummy)
3118                            (action . (lambda (candidate)
3119                                        (org-ref-set-bibtex-keywords helm-pattern)
3120                                        )))))
3121     (helm :sources '(keyword-source fallback-source))))
3122
3123 (defun helm-bibtex-show-entry (key)
3124   "Show the entry for KEY in the BibTeX file.
3125 The original function in `helm-bibtex' has a bug where it finds the
3126 first key that partially matches.  This version avoids that."
3127   (catch 'break
3128     (dolist (bibtex-file (if (listp helm-bibtex-bibliography)
3129                              helm-bibtex-bibliography
3130                            (list helm-bibtex-bibliography)))
3131       (let ((buf (helm-bibtex-buffer-visiting bibtex-file))
3132             (entries '()))
3133         (find-file bibtex-file)
3134         (bibtex-map-entries
3135          (lambda (key start end)
3136            (add-to-list 'entries (cons key start))))
3137         (if (assoc key entries)
3138             (progn
3139               (goto-char (cdr (assoc key entries)))
3140               (throw 'break t))
3141           (unless buf
3142             (kill-buffer)))))))
3143
3144 (defun org-ref-helm-tag-entries (candidates)
3145   "Set tags on selected bibtex entries from `helm-bibtex'.
3146 User is prompted for tags.  This function is called from `helm-bibtex'.
3147 Argument CANDIDATES helm candidates."
3148   (message "")
3149   (let ((keywords (read-string "Keywords (comma separated): ")))
3150     (cl-loop for key in (helm-marked-candidates)
3151              do
3152              (save-window-excursion
3153                (helm-bibtex-show-entry key)
3154                (bibtex-set-field
3155                 "keywords"
3156                 (concat
3157                  keywords
3158                  ", " (bibtex-autokey-get-field "keywords")))
3159                (save-buffer)))))
3160
3161 (setq helm-source-bibtex
3162       '((name                                      . "BibTeX entries")
3163         (init                                      . helm-bibtex-init)
3164         (candidates                                . helm-bibtex-candidates)
3165         (filtered-candidate-transformer            . helm-bibtex-candidates-formatter)
3166         (action . (("Insert citation"              . helm-bibtex-insert-citation)
3167                    ("Show entry"                   . helm-bibtex-show-entry)
3168                    ("Open PDF file (if present)"   . helm-bibtex-open-pdf)
3169                    ("Open URL or DOI in browser"   . helm-bibtex-open-url-or-doi)
3170                    ("Insert formatted reference"   . helm-bibtex-insert-reference)
3171                    ("Insert BibTeX key"            . helm-bibtex-insert-key)
3172                    ("Insert BibTeX entry"          . helm-bibtex-insert-bibtex)
3173                    ("Attach PDF to email"          . helm-bibtex-add-PDF-attachment)
3174                    ("Edit notes"                   . helm-bibtex-edit-notes)
3175                    ("Add keywords to entries"      . org-ref-helm-tag-entries)
3176                    ))))
3177
3178 (defun helm-bibtex-format-org-ref (keys)
3179   "Insert selected KEYS as cite link. Append KEYS if you are on a link.
3180 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.
3181
3182 In the helm-bibtex buffer, C-u will give you a helm menu to select a new link type for the selected entries.
3183
3184 C-u C-u will change the key at point to the selected keys."
3185   (let* ((object (org-element-context))
3186          (last-char (save-excursion
3187                       (when (org-element-property :end object)
3188                         (goto-char (org-element-property :end object))
3189                         (unless (bobp)
3190                           (backward-char))
3191                         (if (looking-at " ")
3192                             " "
3193                           "")))))
3194     (cond
3195      ;; case where we are in a link
3196      ((and (equal (org-element-type object) 'link)
3197            (-contains?
3198             org-ref-cite-types
3199             (org-element-property :type object)))
3200       (cond
3201        ;; no prefix. append keys
3202        ((equal helm-current-prefix-arg nil)
3203         (goto-char (org-element-property :end object))
3204         (while (looking-back " ") (backward-char))
3205         (insert (concat "," (mapconcat 'identity keys ","))))
3206        ;; double prefix, replace key at point
3207        ((equal helm-current-prefix-arg '(16))
3208         (setf (buffer-substring
3209                (org-element-property :begin object)
3210                (org-element-property :end object))
3211               (concat
3212                (replace-regexp-in-string
3213                 (car (org-ref-get-bibtex-key-and-file)) ; key
3214                 (mapconcat 'identity keys ",")          ; new keys
3215                 (org-element-property :raw-link object))
3216                ;; replace space at end to avoid collapsing into next word.
3217                last-char))
3218         ;; and we want to go to the end of the new link
3219         (goto-char
3220          (org-element-property :end (org-element-context))))
3221        (t
3222         (message "Not found"))))
3223
3224      ;; We are next to a link, and we want to append
3225      ;; next to a link means one character back is on a link.
3226      ((save-excursion
3227         (unless (bobp) (backward-char))
3228         (and (equal (org-element-type (org-element-context)) 'link)
3229              (-contains?
3230               org-ref-cite-types
3231               (org-element-property :type (org-element-context)))))
3232       (while (looking-back " ") (backward-char))
3233       (insert (concat "," (mapconcat 'identity keys ","))))
3234
3235      ;; insert fresh link
3236      (t
3237       ;;(message-box "fresh link")
3238       (insert
3239        (concat (if (equal helm-current-prefix-arg '(4))
3240                    (helm :sources `((name . "link types")
3241                                     (candidates . ,org-ref-cite-types)
3242                                     (action . (lambda (x) x))))
3243                org-ref-default-citation-link)
3244                ":"
3245                (s-join "," keys))))))
3246   ;; return empty string for helm
3247   "")
3248
3249 (setq helm-bibtex-format-citation-functions
3250       '((org-mode . helm-bibtex-format-org-ref)))
3251
3252 ;;;###autoload
3253 (defun org-ref-helm-insert-cite-link (arg)
3254   "org-ref function to use helm-bibtex to insert a citation link.
3255 With one prefix arg, insert a ref link.
3256 With two prefix args, insert a label link."
3257   (interactive "P")
3258   (cond
3259    ((equal arg nil)
3260      (let ((helm-bibtex-bibliography (org-ref-find-bibliography)))
3261        (helm-bibtex)))
3262    ((equal arg '(4))
3263     (org-ref-helm-insert-ref-link))
3264    ((equal arg '(16))
3265     (org-ref-helm-insert-label-link))))
3266
3267
3268 ;; add our own fallback entries where we want them. These appear in reverse order of adding in the menu
3269 (setq helm-bibtex-fallback-options
3270       (-insert-at 1 '("Crossref" . "http://search.crossref.org/?q=%s") helm-bibtex-fallback-options))
3271
3272 (setq helm-bibtex-fallback-options
3273       (-insert-at
3274        1
3275        '("Scopus" . "http://www.scopus.com/scopus/search/submit/xadvanced.url?searchfield=TITLE-ABS-KEY(%s)")
3276        helm-bibtex-fallback-options))
3277
3278 (setq helm-bibtex-fallback-options
3279       (-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))
3280
3281 (defun org-ref-get-citation-string-at-point ()
3282   "Get a string of a formatted citation."
3283   (let* ((results (org-ref-get-bibtex-key-and-file))
3284          (key (car results))
3285          (bibfile (cdr results)))
3286     (if bibfile
3287         (save-excursion
3288           (with-temp-buffer
3289             (insert-file-contents bibfile)
3290             (bibtex-set-dialect (parsebib-find-bibtex-dialect) t)
3291             (bibtex-search-entry key)
3292             (org-ref-bib-citation)))
3293       "!!! No entry found !!!" )))
3294
3295
3296 (defun org-ref-cite-candidates ()
3297   "Generate the list of possible candidates for click actions on a cite link.
3298 Checks for pdf and doi, and add appropriate functions."
3299   (let* ((results (org-ref-get-bibtex-key-and-file))
3300          (key (car results))
3301          (pdf-file (funcall org-ref-get-pdf-filename-function key))
3302          (bibfile (cdr results))
3303          (url (save-excursion
3304                 (with-temp-buffer
3305                   (insert-file-contents bibfile)
3306                   (bibtex-set-dialect (parsebib-find-bibtex-dialect) t)
3307                   (bibtex-search-entry key)
3308                   (bibtex-autokey-get-field "url"))))
3309          (doi (save-excursion
3310                 (with-temp-buffer
3311                   (insert-file-contents bibfile)
3312                   (bibtex-set-dialect (parsebib-find-bibtex-dialect) t)
3313                   (bibtex-search-entry key)
3314                   ;; I like this better than bibtex-url which does not always find
3315                   ;; the urls
3316                   (bibtex-autokey-get-field "doi"))))
3317          (candidates `(("Quit" . org-ref-citation-at-point)
3318                        ("Open bibtex entry" . org-ref-open-citation-at-point))))
3319     ;; for some reason, when there is no doi or url, they are returned as "". I
3320     ;; prefer nil so we correct this here.
3321     (when (string= doi "") (setq doi nil))
3322     (when (string= url "") (setq url nil))
3323
3324     ;; Conditional pdf functions
3325     (if (file-exists-p pdf-file)
3326         (add-to-list
3327          'candidates
3328          '("Open pdf" . org-ref-open-pdf-at-point)
3329          t)
3330       (add-to-list
3331        'candidates
3332        '("Try to get pdf" . (lambda ()
3333                               (save-window-excursion
3334                                 (org-ref-open-citation-at-point)
3335                                 (bibtex-beginning-of-entry)
3336                                 (doi-utils-get-bibtex-entry-pdf))))
3337        t))
3338
3339
3340     (add-to-list
3341      'candidates
3342      '("Open notes" . org-ref-open-notes-at-point)
3343      t)
3344
3345     ;; conditional url and doi functions
3346     (when (or url doi)
3347       (add-to-list
3348        'candidates
3349        '("Open in browser" . org-ref-open-url-at-point)
3350        t))
3351
3352     (when doi
3353       (mapc (lambda (x)
3354               (add-to-list 'candidates x t))
3355             `(("WOS" . org-ref-wos-at-point)
3356               ("Related articles in WOS" . org-ref-wos-related-at-point)
3357               ("Citing articles in WOS" . org-ref-wos-citing-at-point)
3358               ("Google Scholar" . org-ref-google-scholar-at-point)
3359               ("Pubmed" . org-ref-pubmed-at-point)
3360               ("Crossref" . org-ref-crossref-at-point)
3361               )))
3362
3363     (add-to-list
3364      'candidates
3365      '("Copy formatted citation to clipboard" . org-ref-copy-entry-as-summary)
3366      t)
3367
3368     (add-to-list
3369      'candidates
3370      '("Copy key to clipboard" . (lambda ()
3371                                   (kill-new
3372                                    (car (org-ref-get-bibtex-key-and-file)))))
3373      t)
3374
3375     (add-to-list
3376      'candidates
3377      '("Copy bibtex entry to file" . org-ref-copy-entry-at-point-to-file)
3378      t)
3379
3380     (add-to-list
3381      'candidates
3382      '("Email bibtex entry and pdf" . (lambda ()
3383                   (save-excursion
3384                     (org-ref-open-citation-at-point)
3385                     (email-bibtex-entry))))
3386      t)
3387   ;; finally return a numbered list of the candidates
3388   (cl-loop for i from 0
3389            for cell in candidates
3390            collect (cons (format "%2s. %s" i (car cell))
3391                          (cdr cell)))))
3392
3393
3394 (defvar org-ref-helm-user-candidates '()
3395   "List of user-defined candidates to act when clicking on a cite link.
3396 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.")
3397
3398 ;; example of adding your own function
3399 (add-to-list
3400  'org-ref-helm-user-candidates
3401  '("Open pdf in emacs" . (lambda ()
3402                            (find-file
3403                             (concat
3404                              org-ref-pdf-directory
3405                              (car (org-ref-get-bibtex-key-and-file))
3406                              ".pdf"))))
3407  t)
3408
3409 ;;;###autoload
3410 (defun org-ref-cite-click-helm (key)
3411   "Open helm for actions on a cite link.
3412 subtle points.
3413
3414 1. get name and candidates before entering helm because we need
3415 the org-buffer.
3416
3417 2. switch back to the org buffer before evaluating the
3418 action.  most of them need the point and buffer.
3419
3420 KEY is returned for the selected item(s) in helm."
3421   (interactive)
3422   (let ((name (org-ref-get-citation-string-at-point))
3423         (candidates (org-ref-cite-candidates))
3424         (cb (current-buffer)))
3425
3426     (helm :sources `(((name . ,name)
3427                       (candidates . ,candidates)
3428                       (action . (lambda (f)
3429                                   (switch-to-buffer cb)
3430                                   (funcall f))))
3431                      ((name . "User functions")
3432                       (candidates . ,org-ref-helm-user-candidates)
3433                       (action . (lambda (f)
3434                                   (switch-to-buffer cb)
3435                                   (funcall f))))
3436                      ))))
3437
3438 ;; * Hydra menus in org-ref
3439
3440 (when (featurep 'hydra)
3441   (require 'hydra)
3442   (setq hydra-is-helpful t)
3443
3444   (defhydra org-ref-cite-hydra (:color blue)
3445     "
3446 _p_: Open pdf     _w_: WOS          _g_: Google Scholar _K_: Copy citation to clipboard
3447 _u_: Open url     _r_: WOS related  _P_: Pubmed         _k_: Copy key to clipboard
3448 _n_: Open notes   _c_: WOS citing   _C_: Crossref       _f_: Copy bibtex entry to file
3449 _o_: Open entry   _e_: Email entry and pdf
3450 "
3451     ("o" org-ref-open-citation-at-point nil)
3452     ("p" org-ref-open-pdf-at-point nil)
3453     ("n" org-ref-open-notes-at-point nil)
3454     ("u" org-ref-open-url-at-point nil)
3455     ("w" org-ref-wos-at-point nil)
3456     ("r" org-ref-wos-related-at-point nil)
3457     ("c" org-ref-wos-citing-at-point nil)
3458     ("g" org-ref-google-scholar-at-point nil)
3459     ("P" org-ref-pubmed-at-point nil)
3460     ("C" org-ref-crossref-at-point nil)
3461     ("K" org-ref-copy-entry-as-summary nil)
3462     ("k" (progn
3463            (kill-new
3464             (car (org-ref-get-bibtex-key-and-file)))) nil)
3465     ("f" org-ref-copy-entry-at-point-to-file nil)
3466
3467     ("e" (save-excursion
3468            (org-ref-open-citation-at-point)
3469            (email-bibtex-entry)) nil)))
3470
3471 ;; * org-ref-help
3472 (defun org-ref-help ()
3473   "Open the org-ref manual."
3474   (interactive)
3475   (find-file (expand-file-name
3476               "org-ref.org"
3477               (file-name-directory
3478                (find-library-name "org-ref")))))
3479
3480 ;; * org-ref menu
3481 (defun org-ref-org-menu ()
3482   "Add org-ref menu to the Org menu."
3483
3484   (easy-menu-change
3485    '("Org") "org-ref"
3486    '( ["Insert citation" org-ref-helm-insert-cite-link]
3487       ["Insert ref" org-ref-helm-insert-ref-link]
3488       ["Insert label" org-ref-helm-insert-label-link]
3489       "--"
3490       ["List of figures" org-ref-list-of-figures]
3491       ["List of tables" org-ref-list-of-tables]
3492       ["Extract bibtex entries" org-ref-extract-bibtex-entries]
3493       ["Check org-file" org-ref]
3494       "--"
3495       ["Help" org-ref-help]
3496       ["Customize org-ref" (customize-group 'org-ref)])
3497    "Show/Hide")
3498
3499   (easy-menu-change '("Org") "--" nil "Show/Hide"))
3500
3501 (add-hook 'org-mode-hook 'org-ref-org-menu)
3502
3503 ;; * The end
3504 (provide 'org-ref)
3505
3506 ;;; org-ref.el ends here