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