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