]> git.donarmstrong.com Git - org-ref.git/blob - org-ref.el
87deb290285bd15b47a05e8535faadba807b627f
[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       "\\(eq\\)?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
752 (defun org-bibliographystyle-complete-link (&optional arg)
753   "Completion function for bibliographystyle link.
754 ARG does nothing."
755   (format "bibliographystyle:%s" (ido-completing-read
756                                   "style: "
757                                   '("unsrt" "plain" "alpha"
758                                     ;; natbib
759                                     ;; https://www.sharelatex.com/learn/Natbib_bibliography_styles
760                                     "dinat" "humannat" "plainnat"
761                                     "abbrnat" "unsrtnat" "rusnat"
762                                     "ksfhnat"))))
763
764
765 (defun org-bibliography-complete-link (&optional arg)
766   "Completion function for bibliography link.
767 ARG does nothing."
768   (format "bibliography:%s" (read-file-name "enter file: " nil nil t)))
769
770
771 (defun org-ref-insert-bibliography-link ()
772   "Insert a bibliography with completion."
773   (interactive)
774   (insert (org-bibliography-complete-link)))
775
776 ;; ** addbibresource
777
778 (org-add-link-type "addbibresource"
779                    ;; this code is run on clicking. The addbibresource
780                    ;; may contain multiple files. this code finds the
781                    ;; one you clicked on and opens it.
782                    (lambda (link-string)
783                        ;; get link-string boundaries
784                        ;; we have to go to the beginning of the line, and then search forward
785
786                      (let* ((bibfile)
787                             ;; object is the link you clicked on
788                             (object (org-element-context))
789
790                             (link-string-beginning)
791                             (link-string-end))
792
793                      (save-excursion
794                        (goto-char (org-element-property :begin object))
795                        (search-forward link-string nil nil 1)
796                        (setq link-string-beginning (match-beginning 0))
797                        (setq link-string-end (match-end 0)))
798
799                        ;; We set the reftex-default-addbibresource
800                        ;; here. it should be a local variable only in
801                        ;; the current buffer. We need this for using
802                        ;; reftex to do citations.
803                        (set (make-local-variable 'reftex-default-addbibresource)
804                             (split-string (org-element-property :path object) ","))
805
806                        ;; now if we have comma separated bibliographies
807                        ;; we find the one clicked on. we want to
808                        ;; search forward to next comma from point
809                        (save-excursion
810                          (if (search-forward "," link-string-end 1 1)
811                              (setq key-end (- (match-end 0) 1)) ; we found a match
812                            (setq key-end (point)))) ; no comma found so take the point
813                        ;; and backward to previous comma from point
814                        (save-excursion
815                          (if (search-backward "," link-string-beginning 1 1)
816                              (setq key-beginning (+ (match-beginning 0) 1)) ; we found a match
817                            (setq key-beginning (point)))) ; no match found
818                        ;; save the key we clicked on.
819                        (setq bibfile (org-ref-strip-string (buffer-substring key-beginning key-end)))
820                        (find-file bibfile))) ; open file on click
821
822                      ;; formatting code
823                    (lambda (keyword desc format)
824                      (cond
825                       ((eq format 'html) (format "")); no output for html
826                       ((eq format 'latex)
827                          ;; write out the latex addbibresource command
828                        (format "\\addbibresource{%s}" keyword)))))
829
830 ;; ** List of figures
831 (defun org-ref-list-of-figures (&optional arg)
832   "Generate buffer with list of figures in them.
833 ARG does nothing."
834   (interactive)
835   (save-excursion (widen)
836   (let* ((c-b (buffer-name))
837          (counter 0)
838          (list-of-figures
839           (org-element-map (org-element-parse-buffer) 'link
840             (lambda (link)
841               "create a link for to the figure"
842               (when
843                   (and (string= (org-element-property :type link) "file")
844                        (string-match-p
845                         "[^.]*\\.\\(png\\|jpg\\|eps\\|pdf\\)$"
846                         (org-element-property :path link)))
847                 (incf counter)
848
849                 (let* ((start (org-element-property :begin link))
850                        (parent (car (cdr (org-element-property :parent link))))
851                        (caption (caaar (plist-get parent :caption)))
852                        (name (plist-get parent :name)))
853                   (if caption
854                       (format
855                        "[[elisp:(progn (switch-to-buffer \"%s\")(widen)(goto-char %s))][figure %s: %s]] %s\n"
856                        c-b start counter (or name "") caption)
857                     (format
858                      "[[elisp:(progn (switch-to-buffer \"%s\")(widen)(goto-char %s))][figure %s: %s]]\n"
859                      c-b start counter (or name "")))))))))
860     (switch-to-buffer "*List of Figures*")
861     (setq buffer-read-only nil)
862     (org-mode)
863     (erase-buffer)
864     (insert (mapconcat 'identity list-of-figures ""))
865     (setq buffer-read-only t)
866     (use-local-map (copy-keymap org-mode-map))
867     (local-set-key "q" #'(lambda () (interactive) (kill-buffer))))))
868
869 (org-add-link-type
870  "list-of-figures"
871  'org-ref-list-of-figures ; on click
872  (lambda (keyword desc format)
873    (cond
874     ((eq format 'latex)
875      (format "\\listoffigures")))))
876
877 ;; ** List of tables
878 (defun org-ref-list-of-tables (&optional arg)
879   "Generate a buffer with a list of tables.
880 ARG does nothing."
881   (interactive)
882   (save-excursion
883   (widen)
884   (let* ((c-b (buffer-name))
885          (counter 0)
886          (list-of-tables
887           (org-element-map (org-element-parse-buffer 'element) 'table
888             (lambda (table)
889               "create a link for to the table"
890               (incf counter)
891               (let ((start (org-element-property :begin table))
892                     (name  (org-element-property :name table))
893                     (caption (caaar (org-element-property :caption table))))
894                 (if caption
895                     (format
896                      "[[elisp:(progn (switch-to-buffer \"%s\")(widen)(goto-char %s))][table %s: %s]] %s\n"
897                      c-b start counter (or name "") caption)
898                   (format
899                    "[[elisp:(progn (switch-to-buffer \"%s\")(widen)(goto-char %s))][table %s: %s]]\n"
900                    c-b start counter (or name ""))))))))
901     (switch-to-buffer "*List of Tables*")
902     (setq buffer-read-only nil)
903     (org-mode)
904     (erase-buffer)
905     (insert (mapconcat 'identity list-of-tables ""))
906     (setq buffer-read-only t)
907     (use-local-map (copy-keymap org-mode-map))
908     (local-set-key "q" #'(lambda () (interactive) (kill-buffer))))))
909
910 (org-add-link-type
911  "list-of-tables"
912  'org-ref-list-of-tables
913  (lambda (keyword desc format)
914    (cond
915     ((eq format 'latex)
916      (format "\\listoftables")))))
917
918 (defun org-ref-count-labels (label)
919   "Counts number of matches for LABEL in the document."
920   (+ (count-matches (format "label:%s\\b[^-:]" label) (point-min) (point-max))
921      ;; for tblname, it is not enough to get word boundary
922      ;; tab-little and tab-little-2 match then.
923      (count-matches (format "^#\\+tblname:\\s-*%s\\b[^-:]" label) (point-min) (point-max))
924      (count-matches (format "\\label{%s}" label) (point-min) (point-max))
925      ;; this is the org-format #+label:
926      (count-matches (format "^#\\+label:\\s-*%s\\b[^-:]" label) (point-min) (point-max))
927      (let ((custom-id-count 0))
928        (org-map-entries
929         (lambda ()
930           (when (string= label (org-entry-get (point) "CUSTOM_ID"))
931             (setq custom-id-count (+ 1 custom-id-count)))))
932        custom-id-count)))
933
934 ;; ** label link
935 (org-add-link-type
936  "label"
937  (lambda (label)
938    "on clicking count the number of label tags used in the buffer. A number greater than one means multiple labels!"
939    (let ((count (org-ref-count-labels label)))
940    (message (format "%s occurence%s"
941                     count
942                     (if (or (= count 0)
943                               (> count 1))
944                         "s"
945                       ""))
946                     (org-ref-count-labels label))))
947  (lambda (keyword desc format)
948    (cond
949     ((eq format 'html) (format "(<label>%s</label>)" path))
950     ((eq format 'latex)
951      (format "\\label{%s}" keyword)))))
952
953 (defun org-label-store-link ()
954   "Store a link to a label.  The output will be a ref to that label."
955   ;; First we have to make sure we are on a label link.
956   (let* ((object (org-element-context)))
957     (when (and (equal (org-element-type object) 'link)
958                (equal (org-element-property :type object) "label"))
959       (org-store-link-props
960        :type "ref"
961        :link (concat "ref:" (org-element-property :path object))))
962
963     ;; Store link on table
964     (when (equal (org-element-type object) 'table)
965       (org-store-link-props
966        :type "ref"
967        :link (concat "ref:" (org-element-property :name object))))
968
969 ;; it turns out this does not work. you can already store a link to a heading with a CUSTOM_ID
970     ;; store link on heading with custom_id
971 ;    (when (and (equal (org-element-type object) 'headline)
972 ;              (org-entry-get (point) "CUSTOM_ID"))
973 ;      (org-store-link-props
974 ;       :type "ref"
975 ;       :link (concat "ref:" (org-entry-get (point) "CUSTOM_ID"))))
976
977     ;; and to #+label: lines
978     (when (and (equal (org-element-type object) 'paragraph)
979                (org-element-property :name object))
980       (org-store-link-props
981        :type "ref"
982        :link (concat "ref:" (org-element-property :name object))))
983 ))
984
985 (add-hook 'org-store-link-functions 'org-label-store-link)
986
987 ;; ** ref link
988 (org-add-link-type
989  "ref"
990  (lambda (label)
991    "on clicking goto the label. Navigate back with C-c &"
992    (org-mark-ring-push)
993    ;; next search from beginning of the buffer
994
995    ;; it is possible you would not find the label if narrowing is in effect
996    (widen)
997
998    (unless
999        (or
1000         ;; our label links
1001         (progn
1002           (goto-char (point-min))
1003           (re-search-forward (format "label:%s\\b" label) nil t))
1004
1005         ;; a latex label
1006         (progn
1007           (goto-char (point-min))
1008           (re-search-forward (format "\\label{%s}" label) nil t))
1009
1010         ;; #+label: name  org-definition
1011         (progn
1012           (goto-char (point-min))
1013           (re-search-forward (format "^#\\+label:\\s-*\\(%s\\)\\b" label) nil t))
1014
1015         ;; org tblname
1016         (progn
1017           (goto-char (point-min))
1018           (re-search-forward (format "^#\\+tblname:\\s-*\\(%s\\)\\b" label) nil t))
1019
1020 ;; Commented out because these ref links do not actually translate correctly in LaTeX.
1021 ;; you need [[#label]] links.
1022         ;; CUSTOM_ID
1023 ;       (progn
1024 ;         (goto-char (point-min))
1025 ;         (re-search-forward (format ":CUSTOM_ID:\s-*\\(%s\\)" label) nil t))
1026         )
1027      ;; we did not find anything, so go back to where we came
1028      (org-mark-ring-goto)
1029      (error "%s not found" label))
1030    (org-show-entry)
1031    (message "go back with (org-mark-ring-goto) `C-c &`"))
1032  ;formatting
1033  (lambda (keyword desc format)
1034    (cond
1035     ((eq format 'html) (format "(<ref>%s</ref>)" path))
1036     ((eq format 'latex)
1037      (format "\\ref{%s}" keyword)))))
1038
1039 (defun org-ref-get-org-labels ()
1040  "Return a list of #+LABEL: labels."
1041   (save-excursion
1042     (goto-char (point-min))
1043     (let ((matches '()))
1044       (while (re-search-forward "^#\\+label:\\s-+\\(.*\\)\\b" (point-max) t)
1045         (add-to-list 'matches (match-string-no-properties 1) t))
1046 matches)))
1047
1048 (defun org-ref-get-custom-ids ()
1049  "Return a list of custom_id properties in the buffer."
1050  (let ((results '()) custom_id)
1051    (org-map-entries
1052     (lambda ()
1053       (let ((custom_id (org-entry-get (point) "CUSTOM_ID")))
1054         (when (not (null custom_id))
1055           (setq results (append results (list custom_id)))))))
1056 results))
1057
1058 (defun org-ref-get-latex-labels ()
1059   "Return list of matchin LaTeX defined labels in buffer."
1060   (save-excursion
1061     (goto-char (point-min))
1062     (let ((matches '()))
1063       (while (re-search-forward "\\\\label{\\([a-zA-z0-9:-]*\\)}" (point-max) t)
1064         (add-to-list 'matches (match-string-no-properties 1) t))
1065 matches)))
1066
1067 (defun org-ref-get-tblnames ()
1068   "Return list of table names in the buffer."
1069   (org-element-map (org-element-parse-buffer 'element) 'table
1070     (lambda (table)
1071       (org-element-property :name table))))
1072
1073 (defun org-ref-get-labels ()
1074   "Return a list of labels in the buffer that you can make a ref link to.
1075 This is used to complete ref links and in helm menus."
1076   (save-excursion
1077     (save-restriction
1078       (widen)
1079       (goto-char (point-min))
1080       (let ((matches '()))
1081         ;; these are the label:stuff  kinds
1082         (while (re-search-forward "[^#+]label:\\([a-zA-z0-9:-]*\\)" (point-max) t)
1083           (add-to-list 'matches (match-string-no-properties 1) t))
1084         (append matches
1085                 (org-ref-get-org-labels)
1086                 (org-ref-get-latex-labels)
1087                 (org-ref-get-tblnames)
1088                 (org-ref-get-custom-ids))))))
1089
1090 (defun org-ref-helm-insert-label-link ()
1091   "Insert a label link. helm just shows you what labels already exist.
1092 If you are on a label link, replace it."
1093   (interactive)
1094   (let* ((labels (org-ref-get-labels))
1095          (cb (current-buffer)))
1096     (helm :sources `(((name . "Existing labels")
1097                       (candidates . ,labels)
1098                       ;; default action is to open to the label
1099                       (action . (lambda (label)
1100                                   ;; unfortunately I do not have markers here
1101                                   (org-open-link-from-string (format "ref:%s" label))))
1102                       ;; if you select a label, replace current one
1103                       (action . (lambda (label)
1104                                   (switch-to-buffer ,cb)
1105                                   (cond
1106                                    ;;  no prefix or on a link
1107                                    ((equal helm-current-prefix-arg nil)
1108                                     (let* ((object (org-element-context))
1109                                            (last-char (save-excursion
1110                                                         (goto-char (org-element-property :end object))
1111                                                         (backward-char)
1112                                                         (if (looking-at " ")
1113                                                             " "
1114                                                           ""))))
1115                                       (when (-contains? '("label")
1116                                                         (org-element-property :type object))
1117                                           ;; we are on a link, so replace it.
1118                                         (setf
1119                                            (buffer-substring
1120                                             (org-element-property :begin object)
1121                                             (org-element-property :end object))
1122                                            (concat
1123                                             (replace-regexp-in-string
1124                                              (org-element-property :path object)
1125                                              label
1126                                              (org-element-property :raw-link object))
1127                                             last-char)))))
1128                                    ;; no prefix options defined
1129                                    ))))
1130                      ;; no matching selection creates a new label
1131                      ((name . "Create new label")
1132                       (dummy)
1133                       ;; default action creates a new label, or replaces old one
1134                       (action .  (lambda (label)
1135                                    (switch-to-buffer ,cb)
1136                                    (let* ((object (org-element-context))
1137                                           (last-char (save-excursion
1138                                                        (goto-char (org-element-property :end object))
1139                                                        (backward-char)
1140                                                        (if (looking-at " ")
1141                                                            " "
1142                                                          ""))))
1143                                      (if (-contains? '("label")
1144                                                      (org-element-property :type object))
1145                                          ;; we are on a link, so replace it.
1146                                          (setf
1147                                           (buffer-substring
1148                                            (org-element-property :begin object)
1149                                            (org-element-property :end object))
1150                                           (concat
1151                                            (replace-regexp-in-string
1152                                             (org-element-property :path object)
1153                                             helm-pattern
1154                                             (org-element-property :raw-link object))
1155                                            last-char))
1156                                        ;; new link
1157                                        (insert
1158                                         (concat
1159                                          "label:"
1160                                          (or label
1161                                              helm-pattern))))))))))))
1162
1163 (defun org-ref-complete-link (&optional arg)
1164   "Completion function for ref links.
1165 Optional argument ARG Does nothing."
1166   (let ((label))
1167     (setq label (completing-read "label: " (org-ref-get-labels)))
1168     (format "ref:%s" label)))
1169
1170 (defun org-ref-insert-ref-link ()
1171   "Completion function for a ref link."
1172  (interactive)
1173  (insert (org-ref-complete-link)))
1174
1175 (defun org-ref-helm-insert-ref-link ()
1176   "Helm menu to insert ref links to labels in the document.
1177 If you are on link, replace with newly selected label.
1178 Use C-u to insert a different kind of ref link.
1179 Use C-u C-u to insert a [[#custom-id]] link"
1180   (interactive)
1181   (let* ((labels (org-ref-get-labels))
1182          (bs (buffer-string))
1183          (contexts (with-temp-buffer
1184                      (insert bs)
1185                      (mapcar 'org-ref-get-label-context labels)))
1186          (cb (current-buffer)))
1187
1188     (helm :input (thing-at-point 'word)
1189           :sources `(((name . "Available labels to ref")
1190                       (candidates . ,(loop for label in labels
1191                                            for context in contexts
1192                                            ;; we do some kludgy adding spaces
1193                                            ;; and bars to make it "easier" to
1194                                            ;; see in helm.
1195                                            collect (cons (concat
1196                                                           label "\n"
1197                                                           (mapconcat
1198                                                            (lambda (x)
1199                                                              (concat "   |" x))
1200                                                            (split-string context "\n")
1201                                                            "\n"
1202                                                            ) "\n\n") label)))
1203                       ;; default action to replace or insert ref link.
1204                       (action . (lambda (label)
1205                                   (switch-to-buffer ,cb)
1206
1207                                   (cond
1208                                    ;;  no prefix or on a link
1209                                    ((equal helm-current-prefix-arg nil)
1210                                     (let* ((object (org-element-context))
1211                                            (last-char (save-excursion
1212                                                         (goto-char (org-element-property :end object))
1213                                                         (backward-char)
1214                                                         (if (looking-at " ")
1215                                                             " "
1216                                                           ""))))
1217                                       (if (-contains? '("ref" "eqref" "pageref" "nameref")
1218                                                       (org-element-property :type object))
1219                                           ;; we are on a link, so replace it.
1220                                           (setf
1221                                            (buffer-substring
1222                                             (org-element-property :begin object)
1223                                             (org-element-property :end object))
1224                                            (concat
1225                                             (replace-regexp-in-string
1226                                              (org-element-property :path object)
1227                                              label
1228                                              (org-element-property :raw-link object))
1229                                             last-char))
1230                                         ;; insert a new link
1231                                         (insert
1232                                          (concat
1233                                           "ref:" label))
1234                                         )))
1235                                    ;; one prefix, alternate ref link
1236                                    ((equal helm-current-prefix-arg '(4))
1237                                     (insert
1238                                      (concat
1239                                       (helm :sources '((name . "Ref link types")
1240                                                        (candidates . ("ref" "eqref" "pageref" "nameref"))
1241                                                        (action . (lambda (x) x))))
1242                                       ":" label)))
1243                                    ;; two prefixes, insert section custom-id link
1244                                    ((equal helm-current-prefix-arg '(16))
1245                                     (insert
1246                                      (format "[[#%s]]" label)))
1247                                    ))
1248                               ))))))
1249
1250 ;; *** pageref link
1251 (org-add-link-type
1252  "pageref"
1253  (lambda (label)
1254    "on clicking goto the label. Navigate back with C-c &"
1255    (org-mark-ring-push)
1256    ;; next search from beginning of the buffer
1257    (widen)
1258    (unless
1259        (or
1260         ;; our label links
1261         (progn
1262           (goto-char (point-min))
1263           (re-search-forward (format "label:%s\\b" label) nil t))
1264
1265         ;; a latex label
1266         (progn
1267           (goto-char (point-min))
1268           (re-search-forward (format "\\label{%s}" label) nil t))
1269
1270         ;; #+label: name  org-definition
1271         (progn
1272           (goto-char (point-min))
1273           (re-search-forward (format "^#\\+label:\\s-*\\(%s\\)\\b" label) nil t))
1274
1275         ;; org tblname
1276         (progn
1277           (goto-char (point-min))
1278           (re-search-forward (format "^#\\+tblname:\\s-*\\(%s\\)\\b" label) nil t))
1279
1280 ;; Commented out because these ref links do not actually translate correctly in LaTeX.
1281 ;; you need [[#label]] links.
1282         ;; CUSTOM_ID
1283 ;       (progn
1284 ;         (goto-char (point-min))
1285 ;         (re-search-forward (format ":CUSTOM_ID:\s-*\\(%s\\)" label) nil t))
1286         )
1287      ;; we did not find anything, so go back to where we came
1288      (org-mark-ring-goto)
1289      (error "%s not found" label))
1290    (message "go back with (org-mark-ring-goto) `C-c &`"))
1291  ;formatting
1292  (lambda (keyword desc format)
1293    (cond
1294     ((eq format 'html) (format "(<pageref>%s</pageref>)" path))
1295     ((eq format 'latex)
1296      (format "\\pageref{%s}" keyword)))))
1297
1298 (defun org-pageref-complete-link (&optional arg)
1299   "Completion function for ref links.
1300 Optional argument ARG Does nothing."
1301   (let ((label))
1302     (setq label (completing-read "label: " (org-ref-get-labels)))
1303     (format "ref:%s" label)))
1304
1305 (defun org-pageref-insert-ref-link ()
1306   "Insert a pageref link with completion."
1307  (interactive)
1308  (insert (org-pageref-complete-link)))
1309
1310 ;; *** nameref link
1311 (org-add-link-type
1312  "nameref"
1313  (lambda (label)
1314    "on clicking goto the label. Navigate back with C-c &"
1315    (org-mark-ring-push)
1316    ;; next search from beginning of the buffer
1317    (widen)
1318    (unless
1319        (or
1320         ;; a latex label
1321         (progn
1322           (goto-char (point-min))
1323           (re-search-forward (format "\\label{%s}" label) nil t))
1324         )
1325      ;; we did not find anything, so go back to where we came
1326      (org-mark-ring-goto)
1327      (error "%s not found" label))
1328    (message "go back with (org-mark-ring-goto) `C-c &`"))
1329  ;formatting
1330  (lambda (keyword desc format)
1331    (cond
1332     ((eq format 'html) (format "(<nameref>%s</nameref>)" path))
1333     ((eq format 'latex)
1334      (format "\\nameref{%s}" keyword)))))
1335
1336 ;; *** eqref link
1337
1338 (org-add-link-type
1339  "eqref"
1340  (lambda (label)
1341    "on clicking goto the label. Navigate back with C-c &"
1342    (org-mark-ring-push)
1343    ;; next search from beginning of the buffer
1344    (widen)
1345    (goto-char (point-min))
1346    (unless
1347        (or
1348         ;; search forward for the first match
1349         ;; our label links
1350         (re-search-forward (format "label:%s" label) nil t)
1351         ;; a latex label
1352         (re-search-forward (format "\\label{%s}" label) nil t)
1353         ;; #+label: name  org-definition
1354         (re-search-forward (format "^#\\+label:\\s-*\\(%s\\)\\b" label) nil t))
1355      (org-mark-ring-goto)
1356      (error "%s not found" label))
1357    (message "go back with (org-mark-ring-goto) `C-c &`"))
1358  ;formatting
1359  (lambda (keyword desc format)
1360    (cond
1361     ((eq format 'html) (format "(<eqref>%s</eqref>)" path))
1362     ((eq format 'latex)
1363      (format "\\eqref{%s}" keyword)))))
1364
1365 ;; ** cite link
1366
1367 (defun org-ref-get-bibtex-key-under-cursor ()
1368   "Return key under the bibtex cursor.
1369 We search forward from
1370 point to get a comma, or the end of the link, and then backwards
1371 to get a comma, or the beginning of the link.  that delimits the
1372 keyword we clicked on.  We also strip the text properties."
1373   (let* ((object (org-element-context))
1374          (link-string (org-element-property :path object)))
1375     ;; you may click on the part before the citations. here we make
1376     ;; sure to move to the beginning so you get the first citation.
1377     (let ((cp (point)))
1378       (goto-char (org-element-property :begin object))
1379       (search-forward link-string (org-element-property :end object))
1380       (goto-char (match-beginning 0))
1381       ;; check if we clicked before the path and move as needed.
1382       (unless (< cp (point))
1383         (goto-char cp)))
1384
1385     (if (not (org-element-property :contents-begin object))
1386         ;; this means no description in the link
1387         (progn
1388           ;; we need the link path start and end
1389           (save-excursion
1390             (goto-char (org-element-property :begin object))
1391             (search-forward link-string nil nil 1)
1392             (setq link-string-beginning (match-beginning 0))
1393             (setq link-string-end (match-end 0)))
1394
1395           ;; The key is the text between commas, or the link boundaries
1396           (save-excursion
1397             (if (search-forward "," link-string-end t 1)
1398                 (setq key-end (- (match-end 0) 1)) ; we found a match
1399               (setq key-end link-string-end))) ; no comma found so take the end
1400           ;; and backward to previous comma from point which defines the start character
1401           (save-excursion
1402             (if (search-backward "," link-string-beginning 1 1)
1403                 (setq key-beginning (+ (match-beginning 0) 1)) ; we found a match
1404               (setq key-beginning link-string-beginning))) ; no match found
1405           ;; save the key we clicked on.
1406           (setq bibtex-key (org-ref-strip-string (buffer-substring key-beginning key-end)))
1407           (set-text-properties 0 (length bibtex-key) nil bibtex-key)
1408           bibtex-key)
1409       ;; link with description. assume only one key
1410       link-string)))
1411
1412 (defun org-ref-find-bibliography ()
1413   "Find the bibliography in the buffer.
1414 This function sets and returns cite-bibliography-files, which is a list of files
1415 either from bibliography:f1.bib,f2.bib
1416 \bibliography{f1,f2}
1417 internal bibliographies
1418
1419 falling back to what the user has set in `org-ref-default-bibliography'"
1420   (catch 'result
1421     (save-excursion
1422       (goto-char (point-min))
1423       ;;  look for a bibliography link
1424       (when (re-search-forward "\\<bibliography:\\([^\]\|\n]+\\)" nil t)
1425         (setq org-ref-bibliography-files
1426               (mapcar 'org-ref-strip-string (split-string (match-string 1) ",")))
1427         (throw 'result org-ref-bibliography-files))
1428
1429
1430       ;; we did not find a bibliography link. now look for \bibliography
1431       (goto-char (point-min))
1432       (when (re-search-forward "\\\\bibliography{\\([^}]+\\)}" nil t)
1433         ;; split, and add .bib to each file
1434         (setq org-ref-bibliography-files
1435               (mapcar (lambda (x) (concat x ".bib"))
1436                       (mapcar 'org-ref-strip-string
1437                               (split-string (match-string 1) ","))))
1438         (throw 'result org-ref-bibliography-files))
1439
1440       ;; no bibliography found. maybe we need a biblatex addbibresource
1441       (goto-char (point-min))
1442       ;;  look for a bibliography link
1443       (when (re-search-forward "addbibresource:\\([^\]\|\n]+\\)" nil t)
1444         (setq org-ref-bibliography-files
1445               (mapcar 'org-ref-strip-string (split-string (match-string 1) ",")))
1446         (throw 'result org-ref-bibliography-files))
1447
1448       ;; we did not find anything. use defaults
1449       (setq org-ref-bibliography-files org-ref-default-bibliography)))
1450
1451     ;; set reftex-default-bibliography so we can search
1452     (set (make-local-variable 'reftex-default-bibliography) org-ref-bibliography-files)
1453     org-ref-bibliography-files)
1454
1455 (defun org-ref-key-in-file-p (key filename)
1456   "Determine if the KEY is in the FILENAME."
1457   (save-current-buffer
1458     (let ((bibtex-files (list filename)))
1459       ;; This is something I am trying because when the bibtex file is open, and
1460       ;; you have added to it, the only way I find to get the update to update
1461       ;; is to close it and reopen it. or to save it and revert it.
1462       (when (get-file-buffer filename)
1463         (set-buffer (get-file-buffer filename))
1464         (save-buffer)
1465         (revert-buffer t t))
1466       (bibtex-search-entry key t))))
1467
1468 (defun org-ref-get-bibtex-key-and-file (&optional key)
1469   "Return the bibtex KEY and file that it is in.  If no key is provided, get one under point."
1470  (let ((org-ref-bibliography-files (org-ref-find-bibliography))
1471        (file))
1472    (unless key
1473      (setq key (org-ref-get-bibtex-key-under-cursor)))
1474    (setq file     (catch 'result
1475                     (loop for file in org-ref-bibliography-files do
1476                           (if (org-ref-key-in-file-p key (file-truename file))
1477                               (throw 'result file)))))
1478    (cons key file)))
1479
1480 ;; *** key at point functions
1481
1482 (defun org-ref-open-pdf-at-point ()
1483   "Open the pdf for bibtex key under point if it exists."
1484   (interactive)
1485   (let* ((results (org-ref-get-bibtex-key-and-file))
1486          (key (car results))
1487          (pdf-file (format (concat org-ref-pdf-directory "%s.pdf") key)))
1488     (if (file-exists-p pdf-file)
1489         (org-open-file pdf-file)
1490 (message "no pdf found for %s" key))))
1491
1492
1493 (defun org-ref-open-url-at-point ()
1494   "Open the url for bibtex key under point."
1495   (interactive)
1496   (let* ((results (org-ref-get-bibtex-key-and-file))
1497          (key (car results))
1498          (bibfile (cdr results)))
1499     (save-excursion
1500       (with-temp-buffer
1501         (insert-file-contents bibfile)
1502         (bibtex-search-entry key)
1503         ;; I like this better than bibtex-url which does not always find
1504         ;; the urls
1505         (catch 'done
1506           (let ((url (bibtex-autokey-get-field "url")))
1507             (when  url
1508               (browse-url (s-trim url))
1509               (throw 'done nil)))
1510
1511           (let ((doi (bibtex-autokey-get-field "doi")))
1512             (when doi
1513               (if (string-match "^http" doi)
1514                   (browse-url doi)
1515                 (browse-url (format "http://dx.doi.org/%s" (s-trim doi))))
1516               (throw 'done nil))))))))
1517
1518
1519 (defun org-ref-open-notes-at-point ()
1520   "Open the notes for bibtex key under point."
1521   (interactive)
1522   (let* ((results (org-ref-get-bibtex-key-and-file))
1523          (key (car results))
1524          (bibfile (cdr results)))
1525     (save-excursion
1526       (with-temp-buffer
1527         (insert-file-contents bibfile)
1528         (bibtex-search-entry key)
1529         (org-ref-open-bibtex-notes)))))
1530
1531
1532 (defun org-ref-citation-at-point ()
1533   "Give message of current citation at point."
1534   (interactive)
1535   (let* ((cb (current-buffer))
1536         (results (org-ref-get-bibtex-key-and-file))
1537         (key (car results))
1538         (bibfile (cdr results)))
1539     (message "%s" (progn
1540                     (with-temp-buffer
1541                       (insert-file-contents bibfile)
1542                       (bibtex-search-entry key)
1543                       (org-ref-bib-citation))))))
1544
1545
1546 (defun org-ref-open-citation-at-point ()
1547   "Open bibtex file to key at point."
1548   (interactive)
1549   (let* ((cb (current-buffer))
1550         (results (org-ref-get-bibtex-key-and-file))
1551         (key (car results))
1552         (bibfile (cdr results)))
1553     (find-file bibfile)
1554     (bibtex-search-entry key)))
1555
1556 ;; *** cite menu
1557
1558 (defvar org-ref-cite-menu-funcs '()
1559  "Functions to run on cite click menu.
1560 Each entry is a list of (key menu-name function).
1561 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.")
1562
1563
1564 (defvar org-ref-user-cite-menu-funcs
1565   '(("C" "rossref" org-ref-crossref-at-point)
1566     ("y" "Copy entry to file" org-ref-copy-entry-at-point-to-file)
1567     ("s" "Copy summary" org-ref-copy-entry-as-summary))
1568   "User-defined functions to run on bibtex key at point.")
1569
1570
1571 (defun org-ref-copy-entry-as-summary ()
1572   "Copy the bibtex entry for the citation at point as a summary."
1573   (interactive)
1574     (save-window-excursion
1575       (org-ref-open-citation-at-point)
1576       (kill-new (org-ref-bib-citation))))
1577
1578
1579 (defun org-ref-copy-entry-at-point-to-file ()
1580   "Copy the bibtex entry for the citation at point to NEW-FILE.
1581 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."
1582   (interactive)
1583   (let ((new-file (ido-completing-read
1584                    "Copy to bibfile: "
1585                    (append org-ref-default-bibliography
1586                            (f-entries "." (lambda (f) (f-ext? f "bib"))))))
1587         (key (org-ref-get-bibtex-key-under-cursor)))
1588     (save-window-excursion
1589       (org-ref-open-citation-at-point)
1590       (bibtex-copy-entry-as-kill))
1591
1592     (let ((bibtex-files (list (file-truename new-file))))
1593       (if (assoc key (bibtex-global-key-alist))
1594           (message "That key already exists in %s" new-file)
1595         ;; add to file
1596         (save-window-excursion
1597           (find-file new-file)
1598           (goto-char (point-max))
1599           ;; make sure we are at the beginning of a line.
1600           (unless (looking-at "^") (insert "\n\n"))
1601           (bibtex-yank)
1602           (save-buffer))))))
1603
1604
1605 (defun org-ref-get-doi-at-point ()
1606   "Get doi for key at point."
1607   (let* ((results (org-ref-get-bibtex-key-and-file))
1608          (key (car results))
1609          (bibfile (cdr results))
1610          doi)
1611     (save-excursion
1612       (with-temp-buffer
1613         (insert-file-contents bibfile)
1614         (bibtex-search-entry key)
1615         (setq doi (bibtex-autokey-get-field "doi"))
1616         ;; in case doi is a url, remove the url part.
1617         (replace-regexp-in-string "^http://dx.doi.org/" "" doi)))))
1618
1619
1620 ;; **** functions that operate on key at point for click menu
1621 (defun org-ref-wos-at-point ()
1622   "Open the doi in wos for bibtex key under point."
1623   (interactive)
1624   (doi-utils-wos (org-ref-get-doi-at-point)))
1625
1626
1627 (defun org-ref-wos-citing-at-point ()
1628   "Open the doi in wos citing articles for bibtex key under point."
1629   (interactive)
1630   (doi-utils-wos-citing (org-ref-get-doi-at-point)))
1631
1632
1633 (defun org-ref-wos-related-at-point ()
1634   "Open the doi in wos related articles for bibtex key under point."
1635   (interactive)
1636   (doi-utils-wos-related (org-ref-get-doi-at-point)))
1637
1638
1639 (defun org-ref-google-scholar-at-point ()
1640   "Open the doi in google scholar for bibtex key under point."
1641   (interactive)
1642   (doi-utils-google-scholar (org-ref-get-doi-at-point)))
1643
1644
1645 (defun org-ref-pubmed-at-point ()
1646   "Open the doi in pubmed for bibtex key under point."
1647   (interactive)
1648   (doi-utils-pubmed (org-ref-get-doi-at-point)))
1649
1650
1651 (defun org-ref-crossref-at-point ()
1652   "Open the doi in crossref for bibtex key under point."
1653   (interactive)
1654   (doi-utils-crossref (org-ref-get-doi-at-point)))
1655
1656 ;; *** Minibuffer menu
1657
1658 (defun org-ref-cite-onclick-minibuffer-menu (&optional link-string)
1659   "Action when a cite link is clicked on.
1660 Provides a menu of context sensitive actions.  If the bibtex entry
1661 has a pdf, you get an option to open it.  If there is a doi, you
1662 get a lot of options.  LINK-STRING is used by the link function."
1663   (interactive)
1664   (let* ((results (org-ref-get-bibtex-key-and-file))
1665          (key (car results))
1666          (pdf-file (format (concat org-ref-pdf-directory "%s.pdf") key))
1667          (bibfile (cdr results))
1668          (url (save-excursion
1669                 (with-temp-buffer
1670                   (insert-file-contents bibfile)
1671                   (bibtex-search-entry key)
1672                   (bibtex-autokey-get-field "url"))))
1673          (doi (save-excursion
1674                 (with-temp-buffer
1675                   (insert-file-contents bibfile)
1676                   (bibtex-search-entry key)
1677                   ;; I like this better than bibtex-url which does not always find
1678                   ;; the urls
1679                   (bibtex-autokey-get-field "doi")))))
1680
1681     (when (string= "" doi) (setq doi nil))
1682     (when (string= "" url) (setq url nil))
1683     (setq org-ref-cite-menu-funcs '())
1684
1685     ;; open action
1686     (when
1687         bibfile
1688       (add-to-list
1689        'org-ref-cite-menu-funcs
1690        '("o" "pen" org-ref-open-citation-at-point)))
1691
1692     ;; pdf
1693     (when (file-exists-p pdf-file)
1694       (add-to-list
1695        'org-ref-cite-menu-funcs
1696        `("p" "df" ,org-ref-open-pdf-function) t))
1697
1698     ;; notes
1699     (add-to-list
1700      'org-ref-cite-menu-funcs
1701      '("n" "otes" org-ref-open-notes-at-point) t)
1702
1703     ;; url
1704     (when (or url doi)
1705       (add-to-list
1706        'org-ref-cite-menu-funcs
1707        '("u" "rl" org-ref-open-url-at-point) t))
1708
1709     ;; doi funcs
1710     (when doi
1711       (add-to-list
1712        'org-ref-cite-menu-funcs
1713        '("w" "os" org-ref-wos-at-point) t)
1714
1715       (add-to-list
1716        'org-ref-cite-menu-funcs
1717        '("c" "iting" org-ref-wos-citing-at-point) t)
1718
1719       (add-to-list
1720        'org-ref-cite-menu-funcs
1721        '("r" "elated" org-ref-wos-related-at-point) t)
1722
1723       (add-to-list
1724        'org-ref-cite-menu-funcs
1725        '("g" "oogle scholar" org-ref-google-scholar-at-point) t)
1726
1727       (add-to-list
1728        'org-ref-cite-menu-funcs
1729        '("P" "ubmed" org-ref-pubmed-at-point) t))
1730
1731     ;; add user functions
1732     (dolist (tup org-ref-user-cite-menu-funcs)
1733       (add-to-list
1734        'org-ref-cite-menu-funcs
1735        tup t))
1736
1737     ;; finally quit
1738     (add-to-list
1739      'org-ref-cite-menu-funcs
1740      '("q" "uit" (lambda ())) t)
1741
1742     ;; now we make a menu
1743     ;; construct menu string as a message
1744     (message
1745      (concat
1746       (let* ((results (org-ref-get-bibtex-key-and-file))
1747              (key (car results))
1748              (bibfile (cdr results)))
1749         (save-excursion
1750           (with-temp-buffer
1751             (insert-file-contents bibfile)
1752             (bibtex-search-entry key)
1753             (org-ref-bib-citation))))
1754       "\n"
1755       (mapconcat
1756        (lambda (tup)
1757          (concat "[" (elt tup 0) "]"
1758                  (elt tup 1) " "))
1759        org-ref-cite-menu-funcs "")))
1760     ;; get the input
1761     (let* ((input (read-char-exclusive))
1762            (choice (assoc
1763                     (char-to-string input) org-ref-cite-menu-funcs)))
1764       ;; now run the function (2nd element in choice)
1765       (when choice
1766         (funcall
1767          (elt
1768           choice
1769           2))))))
1770
1771 ;; *** Generation of the cite links
1772 (defmacro org-ref-make-completion-function (type)
1773   "Macro to make a link completion function for a link of TYPE."
1774   `(defun ,(intern (format "org-%s-complete-link" type)) (&optional arg)
1775      (interactive)
1776      (format "%s:%s"
1777              ,type
1778              (completing-read
1779               "bibtex key: "
1780               (let ((bibtex-files (org-ref-find-bibliography)))
1781                 (bibtex-global-key-alist))))))
1782
1783 (defmacro org-ref-make-format-function (type)
1784   "Macro to make a format function for a link of TYPE."
1785   `(defun ,(intern (format "org-ref-format-%s" type)) (keyword desc format)
1786      (cond
1787       ((eq format 'org)
1788        (mapconcat
1789         (lambda (key)
1790           (format "[[#%s][%s]]" key key))
1791         (org-ref-split-and-strip-string keyword) ","))
1792
1793       ((eq format 'ascii)
1794        (concat "["
1795                (mapconcat
1796                 (lambda (key)
1797                   (format "%s" key))
1798                 (org-ref-split-and-strip-string keyword) ",") "]"))
1799
1800       ((eq format 'html)
1801        (mapconcat
1802         (lambda (key)
1803           (format "<a href=\"#%s\">%s</a>" key key))
1804         (org-ref-split-and-strip-string keyword) ","))
1805
1806       ((eq format 'latex)
1807        (if (string= (substring type -1) "s")
1808            ;; biblatex format for multicite commands, which all end in s. These are formated as \cites{key1}{key2}...
1809            (concat "\\" ,type (mapconcat (lambda (key) (format "{%s}"  key))
1810                                          (org-ref-split-and-strip-string keyword) ""))
1811          ;; bibtex format
1812        (concat "\\" ,type (when desc (org-ref-format-citation-description desc)) "{"
1813                (mapconcat (lambda (key) key) (org-ref-split-and-strip-string keyword) ",")
1814                "}")))
1815       ;; for markdown we generate pandoc citations
1816       ((eq format 'md)
1817        (cond
1818         (desc  ;; pre and or post text
1819          (let* ((text (split-string desc "::"))
1820                 (pre (car text))
1821                 (post (cadr text)))
1822            (concat
1823             (format "[@%s," keyword)
1824             (when pre (format " %s" pre))
1825             (when post (format ", %s" post))
1826             "]")))
1827         (t
1828          (format "[%s]"
1829                  (mapconcat
1830                   (lambda (key) (concat "@" key))
1831                   (org-ref-split-and-strip-string keyword)
1832                   "; "))))))))
1833
1834 (defun org-ref-format-citation-description (desc)
1835   "Return formatted citation description.
1836 If the cite link has a DESC (description), it is optional text
1837 for the citation command.  You can specify pre and post text by
1838 separating these with ::, for example [[cite:key][pre text::post
1839 text]]."
1840   (cond
1841    ((string-match "::" desc)
1842     (format "[%s][%s]" (car (setq results (split-string desc "::"))) (cadr results)))
1843    (t (format "[%s]" desc))))
1844
1845 (defun org-ref-define-citation-link (type &optional key)
1846   "Add a citation link of TYPE for org-ref.
1847 With optional KEY, set the reftex binding. For example:
1848 \(org-ref-define-citation-link \"citez\" ?z) will create a new
1849 citez link, with reftex key of z, and the completion function."
1850   (interactive "sCitation Type: \ncKey: ")
1851
1852   ;; create the formatting function
1853   (eval `(org-ref-make-format-function ,type))
1854
1855   (eval-expression
1856    `(org-add-link-type
1857      ,type
1858      org-ref-cite-onclick-function
1859      (quote ,(intern (format "org-ref-format-%s" type)))))
1860
1861   ;; create the completion function
1862   (eval `(org-ref-make-completion-function ,type))
1863
1864   ;; store new type so it works with adding citations, which checks
1865   ;; for existence in this list
1866   (add-to-list 'org-ref-cite-types type)
1867
1868   ;; and finally if a key is specified, we modify the reftex menu
1869   (when key
1870     (setf (nth 2 (assoc 'org reftex-cite-format-builtin))
1871           (append (nth 2 (assoc 'org reftex-cite-format-builtin))
1872                   `((,key  . ,(concat type ":%l")))))))
1873
1874 ;; create all the link types and their completion functions
1875 (mapcar 'org-ref-define-citation-link org-ref-cite-types)
1876
1877 (defun org-ref-insert-cite-link (alternative-cite)
1878   "Insert a default citation link using reftex.
1879 If you are on a link, it appends to the end of the link,
1880 otherwise, a new link is inserted.  Use a prefix
1881 arg (ALTERNATIVE-CITE) to get a menu of citation types."
1882   (interactive "P")
1883   (org-ref-find-bibliography)
1884   (let* ((object (org-element-context))
1885          (link-string-beginning (org-element-property :begin object))
1886          (link-string-end (org-element-property :end object))
1887          (path (org-element-property :path object)))
1888
1889     (if (not alternative-cite)
1890
1891         (cond
1892          ;; case where we are in a link
1893          ((and (equal (org-element-type object) 'link)
1894                (-contains? org-ref-cite-types (org-element-property :type object)))
1895           (goto-char link-string-end)
1896           ;; sometimes there are spaces at the end of the link
1897           ;; this code moves point pack until no spaces are there
1898           (while (looking-back " ") (backward-char))
1899           (insert (concat "," (mapconcat 'identity (reftex-citation t ?a) ","))))
1900
1901          ;; We are next to a link, and we want to append
1902          ((save-excursion
1903             (backward-char)
1904             (and (equal (org-element-type (org-element-context)) 'link)
1905                  (-contains? org-ref-cite-types (org-element-property :type (org-element-context)))))
1906           (while (looking-back " ") (backward-char))
1907           (insert (concat "," (mapconcat 'identity (reftex-citation t ?a) ","))))
1908
1909          ;; insert fresh link
1910          (t
1911           (insert
1912            (concat org-ref-default-citation-link
1913                    ":"
1914                    (mapconcat 'identity (reftex-citation t) ",")))))
1915
1916       ;; you pressed a C-u so we run this code
1917       (reftex-citation))))
1918
1919 (defun org-ref-insert-cite-with-completion (type)
1920   "Insert a cite link of TYPE with completion."
1921   (interactive (list (ido-completing-read "Type: " org-ref-cite-types)))
1922   (insert (funcall (intern (format "org-%s-complete-link" type)))))
1923
1924 (defun org-ref-store-bibtex-entry-link ()
1925   "Save a citation link to the current bibtex entry.  Save in the default link type."
1926   (interactive)
1927   (let ((link (concat org-ref-default-citation-link
1928                  ":"
1929                  (save-excursion
1930                    (bibtex-beginning-of-entry)
1931                    (reftex-get-bib-field "=key=" (bibtex-parse-entry))))))
1932     (message "saved %s" link)
1933     (push (list link) org-stored-links)
1934     (car org-stored-links)))
1935
1936 ;; ** Index link
1937 (org-add-link-type
1938  "index"
1939  (lambda (path)
1940    (occur path))
1941
1942  (lambda (path desc format)
1943    (cond
1944     ((eq format 'latex)
1945       (format "\\index{%s}" path)))))
1946
1947 ;; this will generate a temporary index of entries in the file.
1948 (org-add-link-type
1949  "printindex"
1950  (lambda (path)
1951    (let ((*index-links* '())
1952          (*initial-letters* '()))
1953
1954      ;; get links
1955      (org-element-map (org-element-parse-buffer) 'link
1956        (lambda (link)
1957          (let ((type (nth 0 link))
1958                (plist (nth 1 link)))
1959
1960            (when (equal (plist-get plist ':type) "index")
1961              (add-to-list
1962               '*index-links*
1963               (cons (plist-get plist :path)
1964                     (format
1965                      "[[elisp:(progn (switch-to-buffer \"%s\") (goto-char %s))][%s]]"
1966 (current-buffer)
1967                      (plist-get plist :begin)  ;; position of link
1968                      ;; grab a description
1969                      (save-excursion
1970                        (goto-char (plist-get plist :begin))
1971                        (if (thing-at-point 'sentence)
1972                            ;; get a sentence
1973                            (replace-regexp-in-string
1974                             "\n" "" (thing-at-point 'sentence))
1975                          ;; or call it a link
1976                          "link")))))))))
1977
1978      ;; sort the links
1979      (setq *index-links*  (cl-sort *index-links* 'string-lessp :key 'car))
1980
1981      ;; now first letters
1982      (dolist (link *index-links*)
1983        (add-to-list '*initial-letters* (substring (car link) 0 1) t))
1984
1985      ;; now create the index
1986      (switch-to-buffer (get-buffer-create "*index*"))
1987      (org-mode)
1988      (erase-buffer)
1989      (insert "#+TITLE: Index\n\n")
1990      (dolist (letter *initial-letters*)
1991        (insert (format "* %s\n" (upcase letter)))
1992        ;; now process the links
1993        (while (and
1994                *index-links*
1995                (string= letter (substring (car (car *index-links*)) 0 1)))
1996          (let ((link (pop *index-links*)))
1997            (insert (format "%s %s\n\n" (car link) (cdr link))))))
1998      (switch-to-buffer "*index*")))
1999  ;; formatting
2000  (lambda (path desc format)
2001    (cond
2002     ((eq format 'latex)
2003       (format "\\printindex")))))
2004
2005 ;; ** Glossary link
2006 (org-add-link-type
2007  "newglossaryentry"
2008  nil ;; no follow action
2009  (lambda (path desc format)
2010    (cond
2011     ((eq format 'latex)
2012      (format "\\newglossaryentry{%s}{%s}" path desc)))))
2013
2014
2015 ;; link to entry
2016 (org-add-link-type
2017  "gls"
2018   nil ;; no follow action
2019  (lambda (path desc format)
2020    (cond
2021     ((eq format 'latex)
2022      (format "\\gls{%s}" path)))))
2023
2024 ;; plural
2025 (org-add-link-type
2026  "glspl"
2027   nil ;; no follow action
2028  (lambda (path desc format)
2029    (cond
2030     ((eq format 'latex)
2031      (format "\\glspl{%s}" path)))))
2032
2033 ;; capitalized link
2034 (org-add-link-type
2035  "Gls"
2036   nil ;; no follow action
2037  (lambda (path desc format)
2038    (cond
2039     ((eq format 'latex)
2040      (format "\\Gls{%s}" path)))))
2041
2042 ;; capitalized link
2043 (org-add-link-type
2044  "Glspl"
2045   nil ;; no follow action
2046  (lambda (path desc format)
2047    (cond
2048     ((eq format 'latex)
2049      (format "\\Glspl{%s}" path)))))
2050
2051 ;; * Utilities
2052 ;; ** create text citations from a bibtex entry
2053 (defun org-ref-bib-citation ()
2054   "From a bibtex entry, create and return a simple citation string.
2055 This assumes you are in an article."
2056
2057   (bibtex-beginning-of-entry)
2058   (let* ((cb (current-buffer))
2059          (bibtex-expand-strings t)
2060          (entry (loop for (key . value) in (bibtex-parse-entry t)
2061                       collect (cons (downcase key) value)))
2062          (title (replace-regexp-in-string "\n\\|\t\\|\s+" " " (reftex-get-bib-field "title" entry)))
2063          (year  (reftex-get-bib-field "year" entry))
2064          (author (replace-regexp-in-string "\n\\|\t\\|\s+" " " (reftex-get-bib-field "author" entry)))
2065          (key (reftex-get-bib-field "=key=" entry))
2066          (journal (reftex-get-bib-field "journal" entry))
2067          (volume (reftex-get-bib-field "volume" entry))
2068          (pages (reftex-get-bib-field "pages" entry))
2069          (doi (reftex-get-bib-field "doi" entry))
2070          (url (reftex-get-bib-field "url" entry))
2071          )
2072     ;;authors, "title", Journal, vol(iss):pages (year).
2073     (format "%s, \"%s\", %s, %s:%s (%s)"
2074             author title journal  volume pages year)))
2075
2076 (defun org-ref-bib-html-citation ()
2077   "From a bibtex entry, create and return a simple citation with html links."
2078
2079   (bibtex-beginning-of-entry)
2080   (let* ((cb (current-buffer))
2081          (bibtex-expand-strings t)
2082          (entry (loop for (key . value) in (bibtex-parse-entry t)
2083                       collect (cons (downcase key) value)))
2084          (title (replace-regexp-in-string "\n\\|\t\\|\s+" " " (reftex-get-bib-field "title" entry)))
2085          (year  (reftex-get-bib-field "year" entry))
2086          (author (replace-regexp-in-string "\n\\|\t\\|\s+" " " (reftex-get-bib-field "author" entry)))
2087          (key (reftex-get-bib-field "=key=" entry))
2088          (journal (reftex-get-bib-field "journal" entry))
2089          (volume (reftex-get-bib-field "volume" entry))
2090          (pages (reftex-get-bib-field "pages" entry))
2091          (doi (reftex-get-bib-field "doi" entry))
2092          (url (reftex-get-bib-field "url" entry))
2093          )
2094     ;;authors, "title", Journal, vol(iss):pages (year).
2095     (concat (format "%s, \"%s\", %s, %s:%s (%s)."
2096                     author title journal  volume pages year)
2097             (when url (format " <a href=\"%s\">link</a>" url))
2098             (when doi (format " <a href=\"http://dx.doi.org/%s\">doi</a>" doi)))
2099     ))
2100
2101 ;; ** Open pdf in bibtex entry
2102 (defun org-ref-open-bibtex-pdf ()
2103   "Open pdf for a bibtex entry, if it exists.
2104 assumes point is in
2105 the entry of interest in the bibfile.  but does not check that."
2106   (interactive)
2107   (save-excursion
2108     (bibtex-beginning-of-entry)
2109     (let* ((bibtex-expand-strings t)
2110            (entry (bibtex-parse-entry t))
2111            (key (reftex-get-bib-field "=key=" entry))
2112            (pdf (format (concat org-ref-pdf-directory "%s.pdf") key)))
2113       (message "%s" pdf)
2114       (if (file-exists-p pdf)
2115           (org-open-link-from-string (format "[[file:%s]]" pdf))
2116         (ding)))))
2117
2118 ;; ** Open notes from bibtex entry
2119
2120 (defun org-ref-open-bibtex-notes ()
2121   "From a bibtex entry, open the notes if they exist, and create a heading if they do not.
2122
2123 I never did figure out how to use reftex to make this happen
2124 non-interactively. the reftex-format-citation function did not
2125 work perfectly; there were carriage returns in the strings, and
2126 it did not put the key where it needed to be. so, below I replace
2127 the carriage returns and extra spaces with a single space and
2128 construct the heading by hand."
2129   (interactive)
2130
2131   (bibtex-beginning-of-entry)
2132   (let* ((cb (current-buffer))
2133          (bibtex-expand-strings t)
2134          (entry (loop for (key . value) in (bibtex-parse-entry t)
2135                       collect (cons (downcase key) value)))
2136          (title (replace-regexp-in-string "\n\\|\t\\|\s+" " " (reftex-get-bib-field "title" entry)))
2137          (year  (reftex-get-bib-field "year" entry))
2138          (author (replace-regexp-in-string "\n\\|\t\\|\s+" " " (reftex-get-bib-field "author" entry)))
2139          (key (reftex-get-bib-field "=key=" entry))
2140          (journal (reftex-get-bib-field "journal" entry))
2141          (volume (reftex-get-bib-field "volume" entry))
2142          (pages (reftex-get-bib-field "pages" entry))
2143          (doi (reftex-get-bib-field "doi" entry))
2144          (url (reftex-get-bib-field "url" entry))
2145          )
2146
2147     ;; save key to clipboard to make saving pdf later easier by pasting.
2148     (with-temp-buffer
2149       (insert key)
2150       (kill-ring-save (point-min) (point-max)))
2151
2152     ;; now look for entry in the notes file
2153     (if  org-ref-bibliography-notes
2154         (find-file-other-window org-ref-bibliography-notes)
2155       (error "Org-ref-bib-bibliography-notes is not set to anything"))
2156
2157     (goto-char (point-min))
2158     ;; put new entry in notes if we don't find it.
2159     (if (re-search-forward (format ":Custom_ID: %s$" key) nil 'end)
2160         (funcall org-ref-open-notes-function)
2161       ;; no entry found, so add one
2162       (insert (format "\n** TODO %s - %s" year title))
2163       (insert (format"
2164  :PROPERTIES:
2165   :Custom_ID: %s
2166   :AUTHOR: %s
2167   :JOURNAL: %s
2168   :YEAR: %s
2169   :VOLUME: %s
2170   :PAGES: %s
2171   :DOI: %s
2172   :URL: %s
2173  :END:
2174 [[cite:%s]] [[file:%s/%s.pdf][pdf]]\n\n"
2175 key author journal year volume pages doi url key org-ref-pdf-directory key))
2176 (save-buffer))))
2177
2178 (defun org-ref-open-notes-from-reftex ()
2179   "Call reftex, and open notes for selected entry."
2180   (interactive)
2181   (let ((bibtex-key )))
2182
2183     ;; now look for entry in the notes file
2184     (if  org-ref-bibliography-notes
2185         (find-file-other-window org-ref-bibliography-notes)
2186       (error "Org-ref-bib-bibliography-notes is not set to anything"))
2187
2188     (goto-char (point-min))
2189
2190     (re-search-forward (format
2191                         ":Custom_ID: %s$"
2192                         (first (reftex-citation t)) nil 'end))
2193     (funcall org-ref-open-notes-function))
2194
2195 ;; ** Open bibtex entry in browser
2196 (defun org-ref-open-in-browser ()
2197   "Open the bibtex entry at point in a browser using the url field or doi field."
2198 (interactive)
2199 (save-excursion
2200   (bibtex-beginning-of-entry)
2201   (catch 'done
2202     (let ((url (bibtex-autokey-get-field "url")))
2203       (when  url
2204         (browse-url url)
2205         (throw 'done nil)))
2206
2207     (let ((doi (bibtex-autokey-get-field "doi")))
2208       (when doi
2209         (if (string-match "^http" doi)
2210             (browse-url doi)
2211           (browse-url (format "http://dx.doi.org/%s" doi)))
2212         (throw 'done nil)))
2213     (message "No url or doi found"))))
2214
2215 ;; ** upload entry to citeulike
2216
2217 (defun org-ref-upload-bibtex-entry-to-citeulike ()
2218   "With point in  a bibtex entry get bibtex string and submit to citeulike.
2219
2220 Relies on the python script /upload_bibtex_citeulike.py being in the user directory."
2221   (interactive)
2222   (message "uploading to citeulike")
2223   (save-restriction
2224     (bibtex-narrow-to-entry)
2225     (let ((startpos (point-min))
2226           (endpos (point-max))
2227           (bibtex-string (buffer-string))
2228           (script (concat "python " starter-kit-dir "/upload_bibtex_citeulike.py&")))
2229       (with-temp-buffer (insert bibtex-string)
2230                         (shell-command-on-region (point-min) (point-max) script t nil nil t)))))
2231
2232 ;; ** Build a pdf of the bibtex file
2233 (defun org-ref-build-full-bibliography ()
2234   "Build pdf of all bibtex entries, and open it."
2235   (interactive)
2236   (let* ((bibfile (file-name-nondirectory (buffer-file-name)))
2237         (bib-base (file-name-sans-extension bibfile))
2238         (texfile (concat bib-base ".tex"))
2239         (pdffile (concat bib-base ".pdf")))
2240     (find-file texfile)
2241     (erase-buffer)
2242     (insert (format "\\documentclass[12pt]{article}
2243 \\usepackage[version=3]{mhchem}
2244 \\usepackage{url}
2245 \\usepackage[numbers]{natbib}
2246 \\usepackage[colorlinks=true, linkcolor=blue, urlcolor=blue, pdfstartview=FitH]{hyperref}
2247 \\usepackage{doi}
2248 \\begin{document}
2249 \\nocite{*}
2250 \\bibliographystyle{unsrtnat}
2251 \\bibliography{%s}
2252 \\end{document}" bib-base))
2253     (save-buffer)
2254     (shell-command (concat "pdflatex " bib-base))
2255     (shell-command (concat "bibtex " bib-base))
2256     (shell-command (concat "pdflatex " bib-base))
2257     (shell-command (concat "pdflatex " bib-base))
2258     (kill-buffer texfile)
2259     (org-open-file pdffile)
2260     ))
2261
2262 ;; ** Extract bibtex entries in org-file
2263
2264 (defun org-ref-extract-bibtex-entries ()
2265   "Extract the bibtex entries referred to by cite links in the current buffer into a src block at the bottom of the current buffer.
2266
2267 If no bibliography is in the buffer the variable
2268 `reftex-default-bibliography' is used."
2269   (interactive)
2270   (let* ((temporary-file-directory (file-name-directory (buffer-file-name)))
2271          (tempname (make-temp-file "extract-bib"))
2272          (contents (buffer-string))
2273          (cb (current-buffer))
2274          basename texfile bibfile results)
2275
2276     ;; open tempfile and insert org-buffer contents
2277     (find-file tempname)
2278     (insert contents)
2279     (setq basename (file-name-sans-extension
2280                     (file-name-nondirectory buffer-file-name))
2281           texfile (concat tempname ".tex")
2282           bibfile (concat tempname ".bib"))
2283
2284     ;; see if we have a bibliography, and insert the default one if not.
2285     (save-excursion
2286       (goto-char (point-min))
2287       (unless (re-search-forward "^bibliography:" (point-max) 'end)
2288         (insert (format "\nbibliography:%s"
2289                         (mapconcat 'identity reftex-default-bibliography ",")))))
2290     (save-buffer)
2291
2292     ;; get a latex file and extract the references
2293     (org-latex-export-to-latex)
2294     (find-file texfile)
2295     (reftex-parse-all)
2296     (reftex-create-bibtex-file bibfile)
2297     (save-buffer)
2298     ;; save results of the references
2299     (setq results (buffer-string))
2300
2301     ;; kill buffers. these are named by basename, not full path
2302     (kill-buffer (concat basename ".bib"))
2303     (kill-buffer (concat basename ".tex"))
2304     (kill-buffer basename)
2305
2306     (delete-file bibfile)
2307     (delete-file texfile)
2308     (delete-file tempname)
2309
2310     ;; Now back to the original org buffer and insert the results
2311     (switch-to-buffer cb)
2312     (when (not (string= "" results))
2313       (save-excursion
2314         (goto-char (point-max))
2315         (insert "\n\n")
2316         (org-insert-heading)
2317         (insert (format " Bibtex entries
2318
2319 #+BEGIN_SRC text :tangle %s
2320 %s
2321 #+END_SRC" (concat (file-name-sans-extension (file-name-nondirectory (buffer-file-name))) ".bib") results))))))
2322
2323 ;; ** Find bad citations
2324 (require 'cl)
2325
2326 (defun index (substring list)
2327   "Return the index of SUBSTRING in a LIST of strings."
2328   (let ((i 0)
2329         (found nil))
2330     (dolist (arg list i)
2331       (if (string-match (concat "^" substring "$") arg)
2332           (progn
2333             (setq found t)
2334             (return i)))
2335       (setq i (+ i 1)))
2336     ;; return counter if found, otherwise return nil
2337     (if found i nil)))
2338
2339
2340 (defun org-ref-find-bad-citations ()
2341   "Create a list of citation keys in an org-file that do not have a bibtex entry in the known bibtex files.
2342
2343 Makes a new buffer with clickable links."
2344   (interactive)
2345   ;; generate the list of bibtex-keys and cited keys
2346   (let* ((bibtex-files (org-ref-find-bibliography))
2347          (bibtex-file-path (mapconcat (lambda (x) (file-name-directory (file-truename x))) bibtex-files ":"))
2348          (bibtex-keys (mapcar (lambda (x) (car x)) (bibtex-global-key-alist)))
2349          (bad-citations '()))
2350
2351     (org-element-map (org-element-parse-buffer) 'link
2352       (lambda (link)
2353         (let ((plist (nth 1 link)))
2354           (when (-contains? org-ref-cite-types (plist-get plist :type))
2355             (dolist (key (org-ref-split-and-strip-string (plist-get plist :path)))
2356               (when (not (index key bibtex-keys))
2357                 (setq
2358                  bad-citations
2359                  (append
2360                   bad-citations
2361                   `(,(format "%s [[elisp:(progn (switch-to-buffer-other-frame \"%s\")(goto-char %s))][not found here]]\n"
2362                              key
2363                              (buffer-name)
2364                              (plist-get plist :begin)))))
2365                 )))))
2366       ;; set with-affilates to t to get citations in a caption
2367       nil nil nil t)
2368
2369     (if bad-citations
2370       (progn
2371         (switch-to-buffer-other-window "*Missing citations*")
2372         (org-mode)
2373         (erase-buffer)
2374         (insert "* List of bad cite links\n")
2375         (insert (mapconcat 'identity bad-citations ""))
2376                                         ;(setq buffer-read-only t)
2377         (use-local-map (copy-keymap org-mode-map))
2378         (local-set-key "q" #'(lambda () (interactive) (kill-buffer))))
2379
2380       (when (get-buffer "*Missing citations*")
2381           (kill-buffer "*Missing citations*"))
2382       (message "No bad cite links found"))))
2383
2384 ;; ** helm interface to bad citations, labels, refs in orgfile
2385 (defun org-ref-bad-cite-candidates ()
2386   "Return a list of conses (key . marker) where key does not exist in the known bibliography files, and marker points to the key."
2387   (let* ((cp (point))                   ; save to return to later
2388          (bibtex-files (org-ref-find-bibliography))
2389          (bibtex-file-path (mapconcat
2390                             (lambda (x)
2391                               (file-name-directory (file-truename x)))
2392                             bibtex-files ":"))
2393          (bibtex-keys (mapcar (lambda (x) (car x))
2394                               (bibtex-global-key-alist)))
2395          (bad-citations '()))
2396
2397     (org-element-map (org-element-parse-buffer) 'link
2398       (lambda (link)
2399         (let ((plist (nth 1 link)))
2400           (when (-contains? org-ref-cite-types (plist-get plist :type))
2401             (dolist (key (org-ref-split-and-strip-string (plist-get plist :path)) )
2402               (when (not (index key bibtex-keys))
2403                 (goto-char (plist-get plist :begin))
2404                 (re-search-forward key)
2405                 (push (cons key (point-marker)) bad-citations)))
2406             )))
2407       ;; add with-affiliates to get cites in caption
2408       nil nil nil t)
2409     (goto-char cp)
2410     bad-citations))
2411
2412
2413 (defun org-ref-bad-ref-candidates ()
2414   "Return a list of conses (ref . marker) where ref is a ref link that does not point to anything (i.e. a label)."
2415   ;; first get a list of legitimate labels
2416   (let ((cp (point))
2417         (labels (org-ref-get-labels))
2418         (bad-refs '()))
2419     ;; now loop over ref links
2420     (goto-char (point-min))
2421     (org-element-map (org-element-parse-buffer) 'link
2422       (lambda (link)
2423         (let ((plist (nth 1 link)))
2424           (when (or  (equal (plist-get plist ':type) "ref")
2425                      (equal (plist-get plist ':type) "eqref")
2426                      (equal (plist-get plist ':type) "pageref")
2427                      (equal (plist-get plist ':type) "nameref"))
2428             (unless (-contains? labels (plist-get plist :path))
2429               (goto-char (plist-get plist :begin))
2430               (add-to-list
2431                'bad-refs
2432                (cons (plist-get plist :path)
2433                      (point-marker))))))))
2434     (goto-char cp)
2435     bad-refs))
2436
2437
2438 (defun org-ref-bad-label-candidates ()
2439   "Return a list of labels where label is multiply defined."
2440   (let ((labels (org-ref-get-labels))
2441         (multiple-labels '()))
2442     (when (not (= (length labels)
2443                   (length (-uniq labels))))
2444       (dolist (label labels)
2445         (when (> (-count (lambda (a)
2446                            (equal a label))
2447                          labels) 1)
2448           ;; this is a multiply defined label.
2449           (let ((cp (point)))
2450             (goto-char (point-min))
2451             (while (re-search-forward
2452                     (format  "[^#+]label:%s\\s-" label) nil t)
2453               (push (cons label (point-marker)) multiple-labels))
2454
2455             (goto-char (point-min))
2456             (while (re-search-forward
2457                     (format  "\\label{%s}\\s-?" label) nil t)
2458               (push (cons label (point-marker)) multiple-labels))
2459
2460             (goto-char (point-min))
2461             (while (re-search-forward
2462                     (format  "^#\\+label:\\s-*%s" label) nil t)
2463               (push (cons label (point-marker)) multiple-labels))
2464
2465             (goto-char (point-min))
2466             (while (re-search-forward
2467                     (format   "^#\\+tblname:\\s-*%s" label) nil t)
2468               (push (cons label (point-marker)) multiple-labels))
2469             (goto-char cp)))))
2470       multiple-labels))
2471
2472 ;;;###autoload
2473 (defun org-ref ()
2474   "Opens a helm interface to actions for org-ref.
2475 Shows bad citations, ref links and labels"
2476   (interactive)
2477   (let ((cb (current-buffer))
2478         (bad-citations (org-ref-bad-cite-candidates))
2479         (bad-refs (org-ref-bad-ref-candidates))
2480         (bad-labels (org-ref-bad-label-candidates)))
2481
2482     (helm :sources `(((name . "Bad citations")
2483                        (candidates . ,bad-citations)
2484                        (action . (lambda (marker)
2485                                    (switch-to-buffer (marker-buffer marker))
2486                                    (goto-char marker))))
2487                      ;;
2488                      ((name . "Bad Labels")
2489                       (candidates . ,bad-labels)
2490                       (action . (lambda (marker)
2491                                    (switch-to-buffer (marker-buffer marker))
2492                                    (goto-char marker))))
2493                      ;;
2494                      ((name . "Bad ref links")
2495                       (candidates . ,bad-refs)
2496                       (action . (lambda (marker)
2497                                           (switch-to-buffer (marker-buffer marker))
2498                                           (goto-char marker))))
2499                      ;;
2500                      ((name . "Utilities")
2501                       (candidates . (("Check buffer again" . org-ref)
2502                                      ("Insert citation" . helm-bibtex)
2503                                      ("Insert label link" . org-ref-helm-insert-label-link)
2504                                      ("Insert ref link" . org-ref-helm-insert-ref-link)
2505                                      ("List of figures" . org-ref-list-of-figures)
2506                                      ("List of tables" . org-ref-list-of-tables)
2507                                      ("Table of contents" . nil)
2508                                      ))
2509                       (action . (lambda (x)
2510                                   (switch-to-buffer ,cb)
2511                                   (funcall x))))
2512                      ;;
2513                      ((name . "Export functions")
2514                       (candidates . (("Extract cited entries" . org-ref-extract-bibtex-entries)
2515                                      ("Export to html and open" . (lambda () (org-open-file (org-html-export-to-html))))
2516                                      ("Export to pdf and open" . (lambda ()
2517                                                                    (org-open-file (org-latex-export-to-pdf))))
2518                                      ("Export to manuscript pdf and open" . ox-manuscript-export-and-build-and-open)
2519                                      ("Export submission manuscript pdf and open" . ox-manuscript-build-submission-manuscript-and-open)
2520
2521                                      ))
2522                       (action . (lambda (x)
2523                                   (switch-to-buffer ,cb)
2524                                   (funcall x))))
2525                       ))))
2526
2527 ;; ** Find non-ascii charaters
2528 (defun org-ref-find-non-ascii-characters ()
2529   "Find non-ascii characters in the buffer.  Useful for cleaning up bibtex files."
2530   (interactive)
2531   (occur "[^[:ascii:]]"))
2532
2533 ;; ** Sort fields in a bibtex entry
2534
2535 (defun org-ref-sort-bibtex-entry ()
2536   "Sort fields of entry in standard order and downcase them."
2537   (interactive)
2538   (bibtex-beginning-of-entry)
2539   (let* ((master '("author" "title" "journal" "volume" "number" "pages" "year" "doi" "url"))
2540          (entry (bibtex-parse-entry))
2541          (entry-fields)
2542          (other-fields)
2543          (type (cdr (assoc "=type=" entry)))
2544          (key (cdr (assoc "=key=" entry))))
2545
2546     ;; these are the fields we want to order that are in this entry
2547     (setq entry-fields (mapcar (lambda (x) (car x)) entry))
2548     ;; we do not want to reenter these fields
2549     (setq entry-fields (remove "=key=" entry-fields))
2550     (setq entry-fields (remove "=type=" entry-fields))
2551
2552     ;;these are the other fields in the entry
2553     (setq other-fields (remove-if-not (lambda(x) (not (member x master))) entry-fields))
2554
2555     (cond
2556      ;; right now we only resort articles
2557      ((string= (downcase type) "article")
2558       (bibtex-kill-entry)
2559       (insert
2560        (concat "@article{" key ",\n"
2561                (mapconcat
2562                 (lambda (field)
2563                   (when (member field entry-fields)
2564                     (format "%s = %s," (downcase field) (cdr (assoc field entry))))) master "\n")
2565                (mapconcat
2566                 (lambda (field)
2567                   (format "%s = %s," (downcase field) (cdr (assoc field entry)))) other-fields "\n")
2568                "\n}\n\n"))
2569       (bibtex-find-entry key)
2570       (bibtex-fill-entry)
2571       (bibtex-clean-entry)
2572        ))))
2573
2574 ;; ** Clean a bibtex entry
2575 (defun org-ref-clean-bibtex-entry(&optional keep-key)
2576   "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"
2577   (interactive "P")
2578   (bibtex-beginning-of-entry)
2579 (end-of-line)
2580   ;; some entries do not have a key or comma in first line. We check and add it, if needed.
2581   (unless (string-match ",$" (thing-at-point 'line))
2582     (end-of-line)
2583     (insert ","))
2584
2585   ;; check for empty pages, and put eid or article id in its place
2586   (let ((entry (bibtex-parse-entry))
2587         (pages (bibtex-autokey-get-field "pages"))
2588         (year (bibtex-autokey-get-field "year"))
2589         (doi  (bibtex-autokey-get-field "doi"))
2590         ;; The Journal of Chemical Physics uses eid
2591         (eid (bibtex-autokey-get-field "eid")))
2592
2593     ;; replace http://dx.doi.org/ in doi. some journals put that in,
2594     ;; but we only want the doi.
2595     (when (string-match "^http://dx.doi.org/" doi)
2596       (bibtex-beginning-of-entry)
2597       (goto-char (car (cdr (bibtex-search-forward-field "doi" t))))
2598       (bibtex-kill-field)
2599       (bibtex-make-field "doi")
2600       (backward-char)
2601       (insert (replace-regexp-in-string "^http://dx.doi.org/" "" doi)))
2602
2603     ;; asap articles often set year to 0, which messes up key
2604     ;; generation. fix that.
2605     (when (string= "0" year)
2606       (bibtex-beginning-of-entry)
2607       (goto-char (car (cdr (bibtex-search-forward-field "year" t))))
2608       (bibtex-kill-field)
2609       (bibtex-make-field "year")
2610       (backward-char)
2611       (insert (read-string "Enter year: ")))
2612
2613     ;; fix pages if they are empty if there is an eid to put there.
2614     (when (string= "-" pages)
2615       (when eid
2616         (bibtex-beginning-of-entry)
2617         ;; this seems like a clunky way to set the pages field.But I
2618         ;; cannot find a better way.
2619         (goto-char (car (cdr (bibtex-search-forward-field "pages" t))))
2620         (bibtex-kill-field)
2621         (bibtex-make-field "pages")
2622         (backward-char)
2623         (insert eid)))
2624
2625     ;; replace naked & with \&
2626     (save-restriction
2627       (bibtex-narrow-to-entry)
2628       (bibtex-beginning-of-entry)
2629       (message "checking &")
2630       (replace-regexp " & " " \\\\& ")
2631       (widen))
2632
2633     ;; generate a key, and if it duplicates an existing key, edit it.
2634     (unless keep-key
2635       (let ((key (bibtex-generate-autokey)))
2636
2637         ;; first we delete the existing key
2638         (bibtex-beginning-of-entry)
2639         (re-search-forward bibtex-entry-maybe-empty-head)
2640         (if (match-beginning bibtex-key-in-head)
2641             (delete-region (match-beginning bibtex-key-in-head)
2642                            (match-end bibtex-key-in-head)))
2643         ;; check if the key is in the buffer
2644         (when (save-excursion
2645                 (bibtex-search-entry key))
2646           (save-excursion
2647             (bibtex-search-entry key)
2648             (bibtex-copy-entry-as-kill)
2649             (switch-to-buffer-other-window "*duplicate entry*")
2650             (bibtex-yank))
2651           (setq key (bibtex-read-key "Duplicate Key found, edit: " key)))
2652
2653         (insert key)
2654         (kill-new key))) ;; save key for pasting
2655
2656     ;; run hooks. each of these operates on the entry with no arguments.
2657     ;; this did not work like  i thought, it gives a symbolp error.
2658     ;; (run-hooks org-ref-clean-bibtex-entry-hook)
2659     (mapcar (lambda (x)
2660               (save-restriction
2661                 (save-excursion
2662                   (funcall x))))
2663             org-ref-clean-bibtex-entry-hook)
2664
2665     ;; sort fields within entry
2666     (org-ref-sort-bibtex-entry)
2667     ;; check for non-ascii characters
2668     (occur "[^[:ascii:]]")
2669     ))
2670
2671 (defun org-ref-get-citation-year (key)
2672   "Get the year of an entry with KEY.  Return year as a string."
2673   (let* ((results (org-ref-get-bibtex-key-and-file key))
2674          (bibfile (cdr results)))
2675     (with-temp-buffer
2676       (insert-file-contents bibfile)
2677       (bibtex-search-entry key nil 0)
2678       (prog1 (reftex-get-bib-field "year" (bibtex-parse-entry t))
2679         ))))
2680
2681 ;; ** Sort cite in cite link
2682 (defun org-ref-sort-citation-link ()
2683  "Replace link at point with sorted link by year."
2684  (interactive)
2685  (let* ((object (org-element-context))
2686         (type (org-element-property :type object))
2687         (begin (org-element-property :begin object))
2688         (end (org-element-property :end object))
2689         (link-string (org-element-property :path object))
2690         keys years data)
2691   (setq keys (org-ref-split-and-strip-string link-string))
2692   (setq years (mapcar 'org-ref-get-citation-year keys))
2693   (setq data (mapcar* (lambda (a b) `(,a . ,b)) years keys))
2694   (setq data (cl-sort data (lambda (x y) (< (string-to-int (car x)) (string-to-int (car y))))))
2695   ;; now get the keys separated by commas
2696   (setq keys (mapconcat (lambda (x) (cdr x)) data ","))
2697   ;; and replace the link with the sorted keys
2698   (cl--set-buffer-substring begin end (concat type ":" keys))))
2699
2700 ;; ** Shift-arrow sorting of keys in a cite link
2701
2702 (defun org-ref-swap-keys (i j keys)
2703  "Swap the KEYS in a list with index I and J."
2704  (let ((tempi (nth i keys)))
2705    (setf (nth i keys) (nth j keys))
2706    (setf (nth j keys) tempi))
2707   keys)
2708
2709
2710 (defun org-ref-swap-citation-link (direction)
2711  "Move citation at point in DIRECTION +1 is to the right, -1 to the left."
2712  (interactive)
2713  (let* ((object (org-element-context))
2714         (type (org-element-property :type object))
2715         (begin (org-element-property :begin object))
2716         (end (org-element-property :end object))
2717         (link-string (org-element-property :path object))
2718         key keys i)
2719    ;;   We only want this to work on citation links
2720    (when (-contains? org-ref-cite-types type)
2721         (setq key (org-ref-get-bibtex-key-under-cursor))
2722         (setq keys (org-ref-split-and-strip-string link-string))
2723         (setq i (index key keys))  ;; defined in org-ref
2724         (if (> direction 0) ;; shift right
2725             (org-ref-swap-keys i (+ i 1) keys)
2726           (org-ref-swap-keys i (- i 1) keys))
2727         (setq keys (mapconcat 'identity keys ","))
2728         ;; and replace the link with the sorted keys
2729         (cl--set-buffer-substring
2730          begin end
2731          (concat
2732           type ":" keys
2733           ;; It seems the space at the end can get consumed, so we see if there
2734           ;; is a space, and add it if so. Sometimes there is a comma or period,
2735           ;; then we do not want a space.
2736           (when
2737               (save-excursion
2738                 (goto-char end)
2739                 (looking-back " ")) " ")))
2740         ;; now go forward to key so we can move with the key
2741         (re-search-forward key)
2742         (goto-char (match-beginning 0)))))
2743
2744 ;; add hooks to make it work
2745 (add-hook 'org-shiftright-hook (lambda () (org-ref-swap-citation-link 1)))
2746 (add-hook 'org-shiftleft-hook (lambda () (org-ref-swap-citation-link -1)))
2747
2748 ;; ** context around org-ref links
2749 (defun org-ref-get-label-context (label)
2750   "Return a string of context around a LABEL."
2751   (save-excursion
2752     (catch 'result
2753       (goto-char (point-min))
2754       (when (re-search-forward
2755              (format "label:%s\\b" label) nil t)
2756         (throw 'result (buffer-substring
2757                         (progn
2758                           (previous-line)
2759                           (beginning-of-line)
2760                           (point))
2761                         (progn
2762                           (forward-line 4)
2763                           (point)))))
2764
2765       (goto-char (point-min))
2766       (when (re-search-forward
2767              (format "\\label{%s}" label) nil t)
2768         (throw 'result (buffer-substring
2769                         (progn
2770                           (previous-line)
2771                           (beginning-of-line)
2772                           (point))
2773                         (progn
2774                           (forward-line 4)
2775                           (point)))))
2776
2777       (goto-char (point-min))
2778       (when (re-search-forward
2779              (format "^#\\+label:\\s-*\\(%s\\)\\b" label) nil t)
2780         (throw 'result (buffer-substring
2781                         (progn
2782                           (previous-line)
2783                           (beginning-of-line)
2784                           (point))
2785                         (progn
2786                           (forward-line 4)
2787                           (point)))))
2788
2789       (goto-char (point-min))
2790       (when (re-search-forward
2791              (format "^#\\+tblname:\\s-*\\(%s\\)\\b" label) nil t)
2792         (throw 'result (buffer-substring
2793                         (progn
2794                           (previous-line)
2795                           (beginning-of-line)
2796                           (point))
2797                         (progn
2798                           (forward-line 4)
2799                           (point)))))
2800       (throw 'result "!!! NO CONTEXT FOUND !!!"))))
2801
2802
2803 (defun org-ref-link-message ()
2804   "Print a minibuffer message about the link that point is on."
2805   (interactive)
2806   (when (eq major-mode 'org-mode)
2807     (let* ((object (org-element-context))
2808            (type (org-element-property :type object)))
2809       (save-excursion
2810         (cond
2811          ;; cite links
2812          ((-contains? org-ref-cite-types type)
2813           (message (org-ref-get-citation-string-at-point)))
2814
2815          ;; message some context about the label we are referring to
2816          ((string= type "ref")
2817           (message "%scount: %s"
2818                    (org-ref-get-label-context
2819                     (org-element-property :path object))
2820                    (org-ref-count-labels
2821                         (org-element-property :path object))))
2822
2823          ((string= type "eqref")
2824           (message "%scount: %s"
2825                    (org-ref-get-label-context
2826                     (org-element-property :path object))
2827                    (org-ref-count-labels
2828                         (org-element-property :path object))))
2829
2830          ;; message the count
2831          ((string= type "label")
2832           (let ((count (org-ref-count-labels
2833                         (org-element-property :path object))))
2834             ;; get plurality on occurrence correct
2835             (message (concat
2836                       (number-to-string count)
2837                       " occurence"
2838                       (when (or (= count 0)
2839                                 (> count 1))
2840                         "s")))))
2841
2842          ((string= type "custom-id")
2843           (save-excursion
2844             (org-open-link-from-string
2845              (format "[[#%s]]" (org-element-property :path object)))
2846             (message "%s" (org-get-heading))))
2847
2848          ;; check if the bibliography files exist.
2849          ((string= type "bibliography")
2850           (let* ((bibfile)
2851                  ;; object is the link you clicked on
2852                  (object (org-element-context))
2853                  (link-string (org-element-property :path object))
2854                  (link-string-beginning)
2855                  (link-string-end))
2856             (save-excursion
2857               (goto-char (org-element-property :begin object))
2858               (search-forward link-string nil nil 1)
2859               (setq link-string-beginning (match-beginning 0))
2860               (setq link-string-end (match-end 0)))
2861
2862              ;; make sure we are in link and not before the :
2863             (when (> link-string-beginning (point))
2864               (goto-char link-string-beginning))
2865
2866             ;; now if we have comma separated bibliographies
2867             ;; we find the one clicked on. we want to
2868             ;; search forward to next comma from point
2869             (save-excursion
2870               (if (search-forward "," link-string-end 1 1)
2871                   (setq key-end (- (match-end 0) 1)) ; we found a match
2872                 (setq key-end (point)))) ; no comma found so take the point
2873
2874             ;; and backward to previous comma from point
2875             (save-excursion
2876               (if (search-backward "," link-string-beginning 1 1)
2877                   (setq key-beginning (+ (match-beginning 0) 1)) ; we found a match
2878                 (setq key-beginning (point)))) ; no match found
2879             ;; save the key we clicked on.
2880             (setq bibfile
2881                   (org-ref-strip-string
2882                    (buffer-substring key-beginning key-end)))
2883             (if (file-exists-p bibfile)
2884                 (message "%s exists." bibfile)
2885               (message "!!! %s NOT FOUND !!!" bibfile))))
2886          )))))
2887
2888 ;; ** aliases
2889 (defalias 'oro 'org-ref-open-citation-at-point)
2890 (defalias 'orc 'org-ref-citation-at-point)
2891 (defalias 'orp 'org-ref-open-pdf-at-point)
2892 (defalias 'oru 'org-ref-open-url-at-point)
2893 (defalias 'orn 'org-ref-open-notes-at-point)
2894 (defalias 'ornr 'org-ref-open-notes-from-reftex)
2895
2896 (defalias 'orib 'org-ref-insert-bibliography-link)
2897 (defalias 'oric 'org-ref-insert-cite-link)
2898 (defalias 'orir 'org-ref-insert-ref-link)
2899 (defalias 'orsl 'org-ref-store-bibtex-entry-link)
2900
2901 (defalias 'orcb 'org-ref-clean-bibtex-entry)
2902
2903 ;; * Helm bibtex setup
2904
2905 (setq helm-bibtex-additional-search-fields '(keywords))
2906
2907 (defun helm-bibtex-candidates-formatter (candidates source)
2908   "Formats BibTeX entries for display in results list.
2909 Argument CANDIDATES helm candidates.
2910 Argument SOURCE the helm source."
2911   (cl-loop
2912    with width = (with-helm-window (helm-bibtex-window-width))
2913    for entry in candidates
2914    for entry = (cdr entry)
2915    for entry-key = (helm-bibtex-get-value "=key=" entry)
2916    if (assoc-string "author" entry 'case-fold)
2917      for fields = '("author" "title" "year" "=has-pdf=" "=has-note=" "=type=")
2918    else
2919      for fields = '("editor" "title" "year" "=has-pdf=" "=has-note=" "=type=")
2920    for fields = (--map (helm-bibtex-clean-string
2921                         (helm-bibtex-get-value it entry " "))
2922                        fields)
2923    for fields = (-update-at 0 'helm-bibtex-shorten-authors fields)
2924    for fields = (append fields
2925                          (list  (or (helm-bibtex-get-value "keywords" entry)
2926                                     "" )))
2927    collect
2928    (cons (s-format "$0 $1 $2 $3 $4$5 $6" 'elt
2929                    (-zip-with (lambda (f w) (truncate-string-to-width f w 0 ?\s))
2930                               fields (list 36 (- width 85) 4 1 1 7 7)))
2931          entry-key)))
2932
2933 ;; * org-ref bibtex keywords
2934 ;; adapted from bibtex-utils.el
2935 ;; these are candidates for selecting keywords/tags
2936 (defun org-ref-bibtex-keywords ()
2937   "Get keywords defined in current bibtex file.
2938 These are in the keywords field, and are comma or semicolon separated."
2939   (save-excursion
2940     (goto-char (point-min))
2941     (let (keywords kstring)
2942       (while (re-search-forward "^\\s-*keywords.*{\\([^}]+\\)}" nil t)
2943         ;; TWS - remove newlines/multiple spaces:
2944         (setq kstring (replace-regexp-in-string "[ \t\n]+" " " (match-string 1)))
2945         (mapc
2946          (lambda (v)
2947            (add-to-list 'keywords v t))
2948          (split-string kstring "\\(,\\|;\\)[ \n]*\\|{\\|}" t)))
2949       keywords)))
2950
2951
2952 (defun org-ref-set-bibtex-keywords (keywords &optional arg)
2953   "Add KEYWORDS to a bibtex entry.
2954 If KEYWORDS is a list, it is converted to a comma-separated
2955 string.  The KEYWORDS are added to the beginning of the
2956 field.  Otherwise KEYWORDS should be a string of comma-separate
2957 keywords.  Optional argument ARG prefix arg to replace keywords."
2958   (interactive "sKeywords: \nP")
2959   (bibtex-set-field
2960    "keywords"
2961    (if arg
2962        ;; replace with arg
2963        (if (listp keywords)
2964            (mapconcat 'identity keywords ", ")
2965          keywords)
2966      ;; else concatentate
2967      (concat
2968       (if (listp keywords)
2969           (mapconcat 'identity keywords ", ")
2970         keywords)
2971       (when (not (string= "" (bibtex-autokey-get-field "keywords")))
2972         (concat ", "  (bibtex-autokey-get-field "keywords"))))))
2973   (save-buffer))
2974
2975
2976 (defun helm-tag-bibtex-entry ()
2977   "Helm interface to add keywords to a bibtex entry.
2978 Run this with the point in a bibtex entry."
2979   (interactive)
2980   (let ((keyword-source `((name . "Existing keywords")
2981                           (candidates . ,(org-ref-bibtex-keywords))
2982                           (action . (lambda (candidate)
2983                                       (org-ref-set-bibtex-keywords
2984                                        (mapconcat
2985                                         'identity
2986                                         (helm-marked-candidates)
2987                                         ", "))))))
2988         (fallback-source `((name . "Add new keywords")
2989                            (dummy)
2990                            (action . (lambda (candidate)
2991                                        (org-ref-set-bibtex-keywords helm-pattern)
2992                                        )))))
2993     (helm :sources '(keyword-source fallback-source))))
2994
2995 (defun helm-bibtex-show-entry (key)
2996   "Show the entry for KEY in the BibTeX file.
2997 The original function in `helm-bibtex' has a bug where it finds the
2998 first key that partially matches.  This version avoids that."
2999   (catch 'break
3000     (dolist (bibtex-file (if (listp helm-bibtex-bibliography)
3001                              helm-bibtex-bibliography
3002                            (list helm-bibtex-bibliography)))
3003       (let ((buf (helm-bibtex-buffer-visiting bibtex-file))
3004             (entries '()))
3005         (find-file bibtex-file)
3006         (bibtex-map-entries
3007          (lambda (key start end)
3008            (add-to-list 'entries (cons key start))))
3009         (if (assoc key entries)
3010             (progn
3011               (goto-char (cdr (assoc key entries)))
3012               (throw 'break t))
3013           (unless buf
3014             (kill-buffer)))))))
3015
3016 (defun org-ref-helm-tag-entries (candidates)
3017   "Set tags on selected bibtex entries from `helm-bibtex'.
3018 User is prompted for tags.  This function is called from `helm-bibtex'.
3019 Argument CANDIDATES helm candidates."
3020   (message "")
3021   (let ((keywords (read-input "Keywords (comma separated): ")))
3022     (loop for key in (helm-marked-candidates)
3023           do
3024           (save-window-excursion
3025             (helm-bibtex-show-entry key)
3026             (bibtex-set-field
3027              "keywords"
3028              (concat
3029               keywords
3030               ", " (bibtex-autokey-get-field "keywords")))
3031             (save-buffer)))))
3032
3033 (setq helm-source-bibtex
3034       '((name                                      . "BibTeX entries")
3035         (init                                      . helm-bibtex-init)
3036         (candidates                                . helm-bibtex-candidates)
3037         (filtered-candidate-transformer            . helm-bibtex-candidates-formatter)
3038         (action . (("Insert citation"              . helm-bibtex-insert-citation)
3039                    ("Show entry"                   . helm-bibtex-show-entry)
3040                    ("Open PDF file (if present)"   . helm-bibtex-open-pdf)
3041                    ("Open URL or DOI in browser"   . helm-bibtex-open-url-or-doi)
3042                    ("Insert formatted reference"   . helm-bibtex-insert-reference)
3043                    ("Insert BibTeX key"            . helm-bibtex-insert-key)
3044                    ("Insert BibTeX entry"          . helm-bibtex-insert-bibtex)
3045                    ("Attach PDF to email"          . helm-bibtex-add-PDF-attachment)
3046                    ("Edit notes"                   . helm-bibtex-edit-notes)
3047                    ("Add keywords to entries"      . org-ref-helm-tag-entries)
3048                    ))))
3049
3050 (defun helm-bibtex-format-org-ref (keys)
3051   "Insert selected KEYS as cite link. Append KEYS if you are on a link.
3052 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.
3053
3054 In the helm-bibtex buffer, C-u will give you a helm menu to select a new link type for the selected entries.
3055
3056 C-u C-u will change the key at point to the selected keys."
3057   (let* ((object (org-element-context))
3058          (last-char (save-excursion
3059                       (goto-char (org-element-property :end object))
3060                       (backward-char)
3061                       (if (looking-at " ")
3062                           " "
3063                         ""))))
3064     (cond
3065      ;; case where we are in a link
3066      ((and (equal (org-element-type object) 'link)
3067            (-contains?
3068             org-ref-cite-types
3069             (org-element-property :type object)))
3070       (cond
3071        ;; no prefix. append keys
3072        ((equal helm-current-prefix-arg nil)
3073         (goto-char (org-element-property :end object))
3074         (while (looking-back " ") (backward-char))
3075         (insert (concat "," (mapconcat 'identity keys ","))))
3076        ;; double prefix, replace key at point
3077        ((equal helm-current-prefix-arg '(16))
3078         (setf (buffer-substring
3079                (org-element-property :begin object)
3080                (org-element-property :end object))
3081               (concat
3082                (replace-regexp-in-string
3083                 (car (org-ref-get-bibtex-key-and-file)) ; key
3084                 (mapconcat 'identity keys ",")          ; new keys
3085                 (org-element-property :raw-link object))
3086                ;; replace space at end to avoid collapsing into next word.
3087                last-char))
3088         ;; and we want to go to the end of the new link
3089         (goto-char
3090          (org-element-property :end (org-element-context))))
3091        (t
3092         (message "Not found"))))
3093
3094      ;; We are next to a link, and we want to append
3095      ;; next to a link means one character back is on a link.
3096      ((save-excursion
3097         (backward-char)
3098         (and (equal (org-element-type (org-element-context)) 'link)
3099              (-contains?
3100               org-ref-cite-types
3101               (org-element-property :type (org-element-context)))))
3102       (while (looking-back " ") (backward-char))
3103       (insert (concat "," (mapconcat 'identity keys ","))))
3104
3105      ;; insert fresh link
3106      (t
3107       ;;(message-box "fresh link")
3108       (insert
3109        (concat (if (equal helm-current-prefix-arg '(4))
3110                    (helm :sources `((name . "link types")
3111                                     (candidates . ,org-ref-cite-types)
3112                                     (action . (lambda (x) x))))
3113                org-ref-default-citation-link)
3114                ":"
3115                (s-join "," keys))))))
3116   ;; return empty string for helm
3117   "")
3118
3119 (setq helm-bibtex-format-citation-functions
3120       '((org-mode . helm-bibtex-format-org-ref)))
3121
3122 ;;;###autoload
3123 (defun org-ref-helm-insert-cite-link (arg)
3124   "org-ref function to use helm-bibtex to insert a citation link.
3125 With one prefix arg, insert a ref link.
3126 With two prefix args, insert a label link."
3127   (interactive "P")
3128   (cond
3129    ((equal arg nil)
3130      (let ((helm-bibtex-bibliography (org-ref-find-bibliography)))
3131        (helm-bibtex)))
3132    ((equal arg '(4))
3133     (org-ref-helm-insert-ref-link))
3134    ((equal arg '(16))
3135     (org-ref-helm-insert-label-link))))
3136
3137
3138 ;; add our own fallback entries where we want them. These appear in reverse order of adding in the menu
3139 (setq helm-bibtex-fallback-options
3140       (-insert-at 1 '("Crossref" . "http://search.crossref.org/?q=%s") helm-bibtex-fallback-options))
3141
3142 (setq helm-bibtex-fallback-options
3143       (-insert-at
3144        1
3145        '("Scopus" . "http://www.scopus.com/scopus/search/submit/xadvanced.url?searchfield=TITLE-ABS-KEY(%s)")
3146        helm-bibtex-fallback-options))
3147
3148 (setq helm-bibtex-fallback-options
3149       (-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))
3150
3151 (defun org-ref-get-citation-string-at-point ()
3152   "Get a string of a formatted citation."
3153   (let* ((results (org-ref-get-bibtex-key-and-file))
3154          (key (car results))
3155          (bibfile (cdr results)))
3156     (if bibfile
3157         (save-excursion
3158           (with-temp-buffer
3159             (insert-file-contents bibfile)
3160             (bibtex-search-entry key)
3161             (org-ref-bib-citation)))
3162       "!!! No entry found !!!" )))
3163
3164
3165 (defun org-ref-cite-candidates ()
3166   "Generate the list of possible candidates for click actions on a cite link.
3167 Checks for pdf and doi, and add appropriate functions."
3168   (let* ((results (org-ref-get-bibtex-key-and-file))
3169          (key (car results))
3170          (pdf-file (format (concat org-ref-pdf-directory "%s.pdf") key))
3171          (bibfile (cdr results))
3172          (url (save-excursion
3173                 (with-temp-buffer
3174                   (insert-file-contents bibfile)
3175                   (bibtex-search-entry key)
3176                   (bibtex-autokey-get-field "url"))))
3177          (doi (save-excursion
3178                 (with-temp-buffer
3179                   (insert-file-contents bibfile)
3180                   (bibtex-search-entry key)
3181                   ;; I like this better than bibtex-url which does not always find
3182                   ;; the urls
3183                   (bibtex-autokey-get-field "doi"))))
3184          (candidates `(("Quit" . org-ref-citation-at-point)
3185                        ("Open bibtex entry" . org-ref-open-citation-at-point))))
3186     ;; for some reason, when there is no doi or url, they are returned as "". I
3187     ;; prefer nil so we correct this here.
3188     (when (string= doi "") (setq doi nil))
3189     (when (string= url "") (setq url nil))
3190
3191     ;; Conditional pdf functions
3192     (if (file-exists-p pdf-file)
3193         (add-to-list
3194          'candidates
3195          '("Open pdf" . org-ref-open-pdf-at-point)
3196          t)
3197       (add-to-list
3198        'candidates
3199        '("Try to get pdf" . (lambda ()
3200                               (save-window-excursion
3201                                 (org-ref-open-citation-at-point)
3202                                 (bibtex-beginning-of-entry)
3203                                 (doi-utils-get-bibtex-entry-pdf))))
3204        t))
3205
3206
3207     (add-to-list
3208      'candidates
3209      '("Open notes" . org-ref-open-notes-at-point)
3210      t)
3211
3212     ;; conditional url and doi functions
3213     (when (or url doi)
3214       (add-to-list
3215        'candidates
3216        '("Open in browser" . org-ref-open-url-at-point)
3217        t))
3218
3219     (when doi
3220       (mapc (lambda (x)
3221               (add-to-list 'candidates x t))
3222             `(("WOS" . org-ref-wos-at-point)
3223               ("Related articles in WOS" . org-ref-wos-related-at-point)
3224               ("Citing articles in WOS" . org-ref-wos-citing-at-point)
3225               ("Google Scholar" . org-ref-google-scholar-at-point)
3226               ("Pubmed" . org-ref-pubmed-at-point)
3227               ("Crossref" . org-ref-crossref-at-point)
3228               )))
3229
3230     (add-to-list
3231      'candidates
3232      '("Copy formatted citation to clipboard" . org-ref-copy-entry-as-summary)
3233      t)
3234
3235     (add-to-list
3236      'candidates
3237      '("Copy key to clipboard" . (lambda ()
3238                                   (kill-new
3239                                    (car (org-ref-get-bibtex-key-and-file)))))
3240      t)
3241
3242     (add-to-list
3243      'candidates
3244      '("Copy bibtex entry to file" . org-ref-copy-entry-at-point-to-file)
3245      t)
3246
3247     (add-to-list
3248      'candidates
3249      '("Email bibtex entry and pdf" . (lambda ()
3250                   (save-excursion
3251                     (org-ref-open-citation-at-point)
3252                     (email-bibtex-entry))))
3253      t)
3254   ;; finally return a numbered list of the candidates
3255   (loop for i from 0
3256         for cell in candidates
3257         collect (cons (format "%2s. %s" i (car cell))
3258                       (cdr cell)))))
3259
3260
3261 (defvar org-ref-helm-user-candidates '()
3262   "List of user-defined candidates to act when clicking on a cite link.
3263 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.")
3264
3265 ;; example of adding your own function
3266 (add-to-list
3267  'org-ref-helm-user-candidates
3268  '("Example" . (lambda () (message-box "You did it!")))
3269  t)
3270
3271 ;;;###autoload
3272 (defun org-ref-cite-click-helm (key)
3273   "Open helm for actions on a cite link.
3274 subtle points.
3275
3276 1. get name and candidates before entering helm because we need
3277 the org-buffer.
3278
3279 2. switch back to the org buffer before evaluating the
3280 action.  most of them need the point and buffer.
3281
3282 KEY is returned for the selected item(s) in helm."
3283   (interactive)
3284   (let ((name (org-ref-get-citation-string-at-point))
3285         (candidates (org-ref-cite-candidates))
3286         (cb (current-buffer)))
3287
3288     (helm :sources `(((name . ,name)
3289                       (candidates . ,candidates)
3290                       (action . (lambda (f)
3291                                   (switch-to-buffer cb)
3292                                   (funcall f))))
3293                      ((name . "User functions")
3294                       (candidates . ,org-ref-helm-user-candidates)
3295                       (action . (lambda (f)
3296                                   (switch-to-buffer cb)
3297                                   (funcall f))))
3298                      ))))
3299
3300 ;; * Hydra menus in org-ref
3301
3302 (when (featurep 'hydra)
3303   (require 'hydra)
3304   (setq hydra-is-helpful t)
3305
3306   (defhydra org-ref-cite-hydra (:color blue)
3307     "
3308 _p_: Open pdf     _w_: WOS          _g_: Google Scholar _K_: Copy citation to clipboard
3309 _u_: Open url     _r_: WOS related  _P_: Pubmed         _k_: Copy key to clipboard
3310 _n_: Open notes   _c_: WOS citing   _C_: Crossref       _f_: Copy bibtex entry to file
3311 _o_: Open entry   _e_: Email entry and pdf
3312 "
3313     ("o" org-ref-open-citation-at-point nil)
3314     ("p" org-ref-open-pdf-at-point nil)
3315     ("n" org-ref-open-notes-at-point nil)
3316     ("u" org-ref-open-url-at-point nil)
3317     ("w" org-ref-wos-at-point nil)
3318     ("r" org-ref-wos-related-at-point nil)
3319     ("c" org-ref-wos-citing-at-point nil)
3320     ("g" org-ref-google-scholar-at-point nil)
3321     ("P" org-ref-pubmed-at-point nil)
3322     ("C" org-ref-crossref-at-point nil)
3323     ("K" org-ref-copy-entry-as-summary nil)
3324     ("k" (progn
3325            (kill-new
3326             (car (org-ref-get-bibtex-key-and-file)))) nil)
3327     ("f" org-ref-copy-entry-at-point-to-file nil)
3328
3329     ("e" (save-excursion
3330            (org-ref-open-citation-at-point)
3331            (email-bibtex-entry)) nil)))
3332
3333 ;; * org-ref-help
3334 (defun org-ref-help ()
3335   "Open the org-ref manual."
3336   (interactive)
3337   (find-file (expand-file-name
3338               "org-ref.org"
3339               (file-name-directory
3340                (find-library-name "org-ref")))))
3341
3342 ;; * org-ref menu
3343 (defun org-ref-org-menu ()
3344   "Add org-ref menu to the Org menu."
3345
3346   (easy-menu-change
3347    '("Org") "org-ref"
3348    '( ["Insert citation" org-ref-helm-insert-cite-link]
3349       ["Insert ref" org-ref-helm-insert-ref-link]
3350       ["Insert label" org-ref-helm-insert-label-link]
3351       "--"
3352       ["List of figures" org-ref-list-of-figures]
3353       ["List of tables" org-ref-list-of-tables]
3354       ["Extract bibtex entries" org-ref-extract-bibtex-entries]
3355       ["Check org-file" org-ref]
3356       "--"
3357       ["Help" org-ref-help]
3358       ["Customize org-ref" (customize-group 'org-ref)])
3359    "Show/Hide")
3360
3361   (easy-menu-change '("Org") "--" nil "Show/Hide"))
3362
3363 (add-hook 'org-mode-hook 'org-ref-org-menu)
3364
3365 ;; * The end
3366 (provide 'org-ref)
3367
3368 ;;; org-ref.el ends here