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