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