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