]> git.donarmstrong.com Git - org-ref.git/blob - org-ref.el
small layout changes, fixed bug in bibliographystyle link
[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   (unless (stringp format) (setq format "\\cite{%l}"))
427
428   (if (and reftex-comment-citations
429            (string-match "%l" reftex-cite-comment-format))
430       (error "Reftex-cite-comment-format contains invalid %%l"))
431
432   (while (string-match
433           "\\(\\`\\|[^%]\\)\\(\\(%\\([0-9]*\\)\\([a-zA-Z]\\)\\)[.,;: ]*\\)"
434           format)
435     (let ((n (string-to-number (match-string 4 format)))
436           (l (string-to-char (match-string 5 format)))
437           rpl b e)
438       (save-match-data
439         (setq rpl
440               (cond
441                ((= l ?l) (concat
442                           (org-ref-reftex-get-bib-field "&key" entry)
443                           (if reftex-comment-citations
444                               reftex-cite-comment-format
445                             "")))
446                ((= l ?a) (reftex-format-names
447                           (reftex-get-bib-names "author" entry)
448                           (or n 2)))
449                ((= l ?A) (car (reftex-get-bib-names "author" entry)))
450                ((= l ?b) (org-ref-reftex-get-bib-field "booktitle" entry "in: %s"))
451                ((= l ?B) (reftex-abbreviate-title
452                           (org-ref-reftex-get-bib-field "booktitle" entry "in: %s")))
453                ((= l ?c) (org-ref-reftex-get-bib-field "chapter" entry))
454                ((= l ?d) (org-ref-reftex-get-bib-field "edition" entry))
455                ((= l ?D) (org-ref-reftex-get-bib-field "doi" entry))
456                ((= l ?e) (reftex-format-names
457                           (reftex-get-bib-names "editor" entry)
458                           (or n 2)))
459                ((= l ?E) (car (reftex-get-bib-names "editor" entry)))
460                ((= l ?h) (org-ref-reftex-get-bib-field "howpublished" entry))
461                ((= l ?i) (org-ref-reftex-get-bib-field "institution" entry))
462                ((= l ?j) (org-ref-reftex-get-bib-field "journal" entry))
463                ((= l ?k) (org-ref-reftex-get-bib-field "key" entry))
464                ((= l ?m) (org-ref-reftex-get-bib-field "month" entry))
465                ((= l ?n) (org-ref-reftex-get-bib-field "number" entry))
466                ((= l ?o) (org-ref-reftex-get-bib-field "organization" entry))
467                ((= l ?p) (org-ref-reftex-get-bib-field "pages" entry))
468                ((= l ?P) (car (split-string
469                                (org-ref-reftex-get-bib-field "pages" entry)
470                                "[- .]+")))
471                ((= l ?s) (org-ref-reftex-get-bib-field "school" entry))
472                ((= l ?S) (org-ref-reftex-get-bib-field "series" entry))
473                ((= l ?u) (org-ref-reftex-get-bib-field "publisher" entry))
474                ((= l ?U) (org-ref-reftex-get-bib-field "url" entry))
475                ((= l ?r) (org-ref-reftex-get-bib-field "address" entry))
476                ;; strip enclosing brackets from title if they are there
477                ((= l ?t) (org-ref-reftex-get-bib-field "title" entry))
478                ((= l ?T) (reftex-abbreviate-title
479                           (org-ref-reftex-get-bib-field "title" entry)))
480                ((= l ?v) (org-ref-reftex-get-bib-field "volume" entry))
481                ((= l ?y) (org-ref-reftex-get-bib-field "year" entry)))))
482
483       (if (string= rpl "")
484           (setq b (match-beginning 2) e (match-end 2))
485         (setq b (match-beginning 3) e (match-end 3)))
486       (setq format (concat (substring format 0 b) rpl (substring format e)))))
487   (while (string-match "%%" format)
488     (setq format (replace-match "%" t t format)))
489   (while (string-match "[ ,.;:]*%<" format)
490     (setq format (replace-match "" t t format)))
491   ;; also replace carriage returns, tabs, and multiple whitespaces
492   (setq format (replace-regexp-in-string "\n\\|\t\\|\s+" " " format))
493   format)
494
495 (defun org-ref-get-bibtex-entry-citation (key)
496   "Return a string for the bibliography entry corresponding to KEY.
497 Format according to the type in `org-ref-bibliography-entry-format'."
498
499   (let ((org-ref-bibliography-files (org-ref-find-bibliography))
500         (file) (entry) (bibtex-entry) (entry-type) (format))
501
502     (setq file (catch 'result
503                  (loop for file in org-ref-bibliography-files do
504                        (if (org-ref-key-in-file-p key (file-truename file))
505                            (throw 'result file)
506                          (message "%s not found in %s"
507                                   key (file-truename file))))))
508
509     (with-temp-buffer
510       (insert-file-contents file)
511       (bibtex-search-entry key nil 0)
512       (setq bibtex-entry (bibtex-parse-entry))
513       (setq entry-type (downcase (cdr (assoc "=type=" bibtex-entry))))
514       (setq format (cdr (assoc entry-type org-ref-bibliography-entry-format)))
515       (if format
516           (setq entry  (org-ref-reftex-format-citation bibtex-entry format))
517         (save-restriction
518           (bibtex-narrow-to-entry)
519           (setq entry (buffer-string)))))
520     entry))
521
522 (defun org-ref-get-bibtex-keys ()
523   "Return a list of unique keys in the buffer."
524   (let ((keys '()))
525     (org-element-map (org-element-parse-buffer) 'link
526       (lambda (link)
527         (let ((plist (nth 1 link)))
528           (when (-contains? org-ref-cite-types (plist-get plist ':type))
529             (dolist
530                 (key
531                  (org-ref-split-and-strip-string (plist-get plist ':path)))
532               (when (not (-contains? keys key))
533                 (setq keys (append keys (list key))))))))
534       ;; set with-affiliated to get keys in captions
535       nil nil nil t)
536     ;; Sort keys alphabetically
537     (setq keys (cl-sort keys 'string-lessp :key 'downcase))
538     keys))
539
540 (defun org-ref-get-bibtex-entry-html (key)
541   "Return an html string for the bibliography entry corresponding to KEY."
542   (format "<li><a id=\"%s\">[%s] %s</a></li>"
543           key key (org-ref-get-bibtex-entry-citation key)))
544
545 (defun org-ref-get-html-bibliography ()
546   "Create an html bibliography when there are keys."
547   (let ((keys (org-ref-get-bibtex-keys)))
548     (when keys
549       (concat "<h1>Bibliography</h1>
550 <ul>"
551               (mapconcat (lambda (x) (org-ref-get-bibtex-entry-html x)) keys "\n")
552               "\n</ul>"))))
553
554 (defun org-ref-get-bibtex-entry-org (key)
555   "Return an org string for the bibliography entry corresponding to KEY."
556   (let ((org-ref-bibliography-files (org-ref-find-bibliography))
557         (file) (entry) (bibtex-entry) (entry-type) (format))
558
559     (setq file (catch 'result
560                  (loop for file in org-ref-bibliography-files do
561                        (if (org-ref-key-in-file-p key (file-truename file))
562                            (throw 'result file)
563                          (message "%s not found in %s" key (file-truename file))))))
564
565     (with-temp-buffer
566       (insert-file-contents file)
567       (bibtex-search-entry key nil 0)
568       (setq entry (bibtex-parse-entry))
569       (format "** %s - %s
570   :PROPERTIES:
571   %s
572   :END:
573 " (org-ref-reftex-get-bib-field "author" entry)
574 (org-ref-reftex-get-bib-field "title" entry)
575 (concat "   :CUSTOM_ID: " (org-ref-reftex-get-bib-field "=key=" entry) "\n"
576         (mapconcat (lambda (element) (format "   :%s: %s"
577                                              (upcase (car element))
578                                              (cdr element)))
579                    entry
580                    "\n"))))))
581
582 (defun org-ref-get-org-bibliography ()
583   "Create an org bibliography when there are keys."
584   (let ((keys (org-ref-get-bibtex-keys)))
585     (when keys
586       (concat "* Bibliography
587 "
588               (mapconcat (lambda (x) (org-ref-get-bibtex-entry-org x)) keys "\n")
589               "\n"))))
590
591 (defun org-ref-get-bibtex-entry-ascii (key)
592   "Return an ascii string for the bibliography entry corresponding to KEY."
593
594   (format "[%s] %s" key (org-ref-get-bibtex-entry-citation key)))
595
596 (defun org-ref-get-ascii-bibliography ()
597   "Create an html bibliography when there are keys."
598   (let ((keys (org-ref-get-bibtex-keys)))
599     (when keys
600       (concat
601 "Bibliography
602 =============
603 "
604               (mapconcat (lambda (x) (org-ref-get-bibtex-entry-ascii x)) keys "\n")
605               "\n"))))
606
607 ;; * Links
608 ;; ** bibliography and bibliographystyle
609 (org-add-link-type "bibliography"
610                    ;; this code is run on clicking. The bibliography
611                    ;; may contain multiple files. this code finds the
612                    ;; one you clicked on and opens it.
613                    (lambda (link-string)
614                        ;; get link-string boundaries we have to go to the
615                        ;; beginning of the line, and then search forward
616                      (let* ((bibfile)
617                             ;; object is the link you clicked on
618                             (object (org-element-context))
619                             (link-string-beginning)
620                             (link-string-end)
621                             (cp (point)))
622                      (save-excursion
623                        (goto-char (org-element-property :begin object))
624                        (search-forward link-string nil nil 1)
625                        (setq link-string-beginning (match-beginning 0))
626                        (setq link-string-end (match-end 0)))
627
628                      ;; Make sure point is in the link-path.
629                      (if (< cp link-string-beginning)
630                          (goto-char link-string-beginning))
631                      ;; We set the reftex-default-bibliography
632                      ;; here. it should be a local variable only in
633                      ;; the current buffer. We need this for using
634                      ;; reftex to do citations.
635                      (set (make-local-variable 'reftex-default-bibliography)
636                           (split-string
637                            (org-element-property :path object) ","))
638
639                      ;; now if we have comma separated bibliographies
640                      ;; we find the one clicked on. we want to
641                      ;; search forward to next comma from point
642                      (save-excursion
643                        (if (search-forward "," link-string-end 1 1)
644                            ;; we found a match
645                            (setq key-end (- (match-end 0) 1))
646                          ;; no comma found so take the point
647                          (setq key-end (point))))
648                      ;; and backward to previous comma from point
649                      (save-excursion
650                        (if (search-backward "," link-string-beginning 1 1)
651                            ;; we found a match
652                            (setq key-beginning (+ (match-beginning 0) 1))
653                          (setq key-beginning (point)))) ; no match found
654                        ;; save the key we clicked on.
655                      (setq bibfile (org-ref-strip-string
656                                     (buffer-substring key-beginning key-end)))
657                      ;; open file on click
658                      (find-file bibfile)))
659
660                    ;; formatting code
661                    (lambda (keyword desc format)
662                      (cond
663                       ((eq format 'org) (org-ref-get-org-bibliography))
664                       ((eq format 'ascii) (org-ref-get-ascii-bibliography))
665                       ((eq format 'html) (org-ref-get-html-bibliography))
666                       ((eq format 'latex)
667                        ;; write out the latex bibliography command
668                        (format "\\bibliography{%s}"
669                                (replace-regexp-in-string
670                                 "\\.bib" ""
671                                 (mapconcat
672                                  'identity
673                                  (mapcar 'expand-file-name
674                                          (split-string keyword ","))
675                                  ",")))))))
676
677 (org-add-link-type "nobibliography"
678                    ;; this code is run on clicking. The bibliography
679                    ;; may contain multiple files. this code finds the
680                    ;; one you clicked on and opens it.
681                    (lambda (link-string)
682                        ;; get link-string boundaries
683                        ;; we have to go to the beginning of the line, and then search forward
684
685                      (let* ((bibfile)
686                             ;; object is the link you clicked on
687                             (object (org-element-context))
688
689                             (link-string-beginning)
690                             (link-string-end))
691
692                      (save-excursion
693                        (goto-char (org-element-property :begin object))
694                        (search-forward link-string nil nil 1)
695                        (setq link-string-beginning (match-beginning 0))
696                        (setq link-string-end (match-end 0)))
697
698                        ;; We set the reftex-default-bibliography
699                        ;; here. it should be a local variable only in
700                        ;; the current buffer. We need this for using
701                        ;; reftex to do citations.
702                        (set (make-local-variable 'reftex-default-bibliography)
703                             (split-string (org-element-property :path object) ","))
704
705                        ;; now if we have comma separated bibliographies
706                        ;; we find the one clicked on. we want to
707                        ;; search forward to next comma from point
708                        (save-excursion
709                          (if (search-forward "," link-string-end 1 1)
710                              (setq key-end (- (match-end 0) 1)) ; we found a match
711                            (setq key-end (point)))) ; no comma found so take the point
712                        ;; and backward to previous comma from point
713                        (save-excursion
714                          (if (search-backward "," link-string-beginning 1 1)
715                              (setq key-beginning (+ (match-beginning 0) 1)) ; we found a match
716                            (setq key-beginning (point)))) ; no match found
717                        ;; save the key we clicked on.
718                        (setq bibfile (org-ref-strip-string (buffer-substring key-beginning key-end)))
719                        (find-file bibfile))) ; open file on click
720
721                      ;; formatting code
722                    (lambda (keyword desc format)
723                      (cond
724                       ((eq format 'org) (org-ref-get-org-bibliography))
725                       ((eq format 'ascii) (org-ref-get-ascii-bibliography))
726                       ((eq format 'html) (org-ref-get-html-bibliography))
727                       ((eq format 'latex)
728                        ;; write out the latex bibliography command
729                        (format "\\nobibliography{%s}"
730                                (replace-regexp-in-string  "\\.bib" "" (mapconcat 'identity
731                                                                                  (mapcar 'expand-file-name
732                                                                                          (split-string keyword ","))
733                                                                                  ",")))))))
734
735 (org-add-link-type "printbibliography"
736                    (lambda (arg) (message "Nothing implemented for clicking here."))
737                    (lambda (keyword desc format)
738                      (cond
739                       ((eq format 'org) (org-ref-get-org-bibliography))
740                       ((eq format 'html) (org-ref-get-html-bibliography))
741                       ((eq format 'latex)
742                        ;; write out the biblatex bibliography command
743                        "\\printbibliography"))))
744
745 (org-add-link-type "bibliographystyle"
746                    (lambda (arg) (message "Nothing implemented for clicking here."))
747                    (lambda (keyword desc format)
748                      (cond
749                       ((eq format 'latex)
750                        ;; write out the latex bibliography command
751                        (format "\\bibliographystyle{%s}" keyword))
752                       ;; Other styles should not have an output for this
753                       (t
754                        ""))))
755
756
757 (defun org-bibliographystyle-complete-link (&optional arg)
758   "Completion function for bibliographystyle link.
759 ARG does nothing."
760   (format "bibliographystyle:%s" (ido-completing-read
761                                   "style: "
762                                   '("unsrt" "plain" "alpha"
763                                     ;; natbib
764                                     ;; https://www.sharelatex.com/learn/Natbib_bibliography_styles
765                                     "dinat" "humannat" "plainnat"
766                                     "abbrnat" "unsrtnat" "rusnat"
767                                     "ksfhnat"))))
768
769
770 (defun org-bibliography-complete-link (&optional arg)
771   "Completion function for bibliography link.
772 ARG does nothing."
773   (format "bibliography:%s" (read-file-name "enter file: " nil nil t)))
774
775
776 (defun org-ref-insert-bibliography-link ()
777   "Insert a bibliography with completion."
778   (interactive)
779   (insert (org-bibliography-complete-link)))
780
781 ;; ** addbibresource
782
783 (org-add-link-type "addbibresource"
784                    ;; this code is run on clicking. The addbibresource
785                    ;; may contain multiple files. this code finds the
786                    ;; one you clicked on and opens it.
787                    (lambda (link-string)
788                        ;; get link-string boundaries
789                        ;; we have to go to the beginning of the line, and then search forward
790
791                      (let* ((bibfile)
792                             ;; object is the link you clicked on
793                             (object (org-element-context))
794
795                             (link-string-beginning)
796                             (link-string-end))
797
798                      (save-excursion
799                        (goto-char (org-element-property :begin object))
800                        (search-forward link-string nil nil 1)
801                        (setq link-string-beginning (match-beginning 0))
802                        (setq link-string-end (match-end 0)))
803
804                        ;; We set the reftex-default-addbibresource
805                        ;; here. it should be a local variable only in
806                        ;; the current buffer. We need this for using
807                        ;; reftex to do citations.
808                        (set (make-local-variable 'reftex-default-addbibresource)
809                             (split-string (org-element-property :path object) ","))
810
811                        ;; now if we have comma separated bibliographies
812                        ;; we find the one clicked on. we want to
813                        ;; search forward to next comma from point
814                        (save-excursion
815                          (if (search-forward "," link-string-end 1 1)
816                              (setq key-end (- (match-end 0) 1)) ; we found a match
817                            (setq key-end (point)))) ; no comma found so take the point
818                        ;; and backward to previous comma from point
819                        (save-excursion
820                          (if (search-backward "," link-string-beginning 1 1)
821                              (setq key-beginning (+ (match-beginning 0) 1)) ; we found a match
822                            (setq key-beginning (point)))) ; no match found
823                        ;; save the key we clicked on.
824                        (setq bibfile (org-ref-strip-string (buffer-substring key-beginning key-end)))
825                        (find-file bibfile))) ; open file on click
826
827                      ;; formatting code
828                    (lambda (keyword desc format)
829                      (cond
830                       ((eq format 'html) (format "")); no output for html
831                       ((eq format 'latex)
832                          ;; write out the latex addbibresource command
833                        (format "\\addbibresource{%s}" keyword)))))
834
835 ;; ** List of figures
836 (defun org-ref-list-of-figures (&optional arg)
837   "Generate buffer with list of figures in them.
838 ARG does nothing."
839   (interactive)
840   (save-excursion (widen)
841   (let* ((c-b (buffer-name))
842          (counter 0)
843          (list-of-figures
844           (org-element-map (org-element-parse-buffer) 'link
845             (lambda (link)
846               "create a link for to the figure"
847               (when
848                   (and (string= (org-element-property :type link) "file")
849                        (string-match-p
850                         "[^.]*\\.\\(png\\|jpg\\|eps\\|pdf\\)$"
851                         (org-element-property :path link)))
852                 (incf counter)
853
854                 (let* ((start (org-element-property :begin link))
855                        (parent (car (cdr (org-element-property :parent link))))
856                        (caption (caaar (plist-get parent :caption)))
857                        (name (plist-get parent :name)))
858                   (if caption
859                       (format
860                        "[[elisp:(progn (switch-to-buffer \"%s\")(widen)(goto-char %s))][figure %s: %s]] %s\n"
861                        c-b start counter (or name "") caption)
862                     (format
863                      "[[elisp:(progn (switch-to-buffer \"%s\")(widen)(goto-char %s))][figure %s: %s]]\n"
864                      c-b start counter (or name "")))))))))
865     (switch-to-buffer "*List of Figures*")
866     (setq buffer-read-only nil)
867     (org-mode)
868     (erase-buffer)
869     (insert (mapconcat 'identity list-of-figures ""))
870     (setq buffer-read-only t)
871     (use-local-map (copy-keymap org-mode-map))
872     (local-set-key "q" #'(lambda () (interactive) (kill-buffer))))))
873
874 (org-add-link-type
875  "list-of-figures"
876  'org-ref-list-of-figures ; on click
877  (lambda (keyword desc format)
878    (cond
879     ((eq format 'latex)
880      (format "\\listoffigures")))))
881
882 ;; ** List of tables
883 (defun org-ref-list-of-tables (&optional arg)
884   "Generate a buffer with a list of tables.
885 ARG does nothing."
886   (interactive)
887   (save-excursion
888   (widen)
889   (let* ((c-b (buffer-name))
890          (counter 0)
891          (list-of-tables
892           (org-element-map (org-element-parse-buffer 'element) 'table
893             (lambda (table)
894               "create a link for to the table"
895               (incf counter)
896               (let ((start (org-element-property :begin table))
897                     (name  (org-element-property :name table))
898                     (caption (caaar (org-element-property :caption table))))
899                 (if caption
900                     (format
901                      "[[elisp:(progn (switch-to-buffer \"%s\")(widen)(goto-char %s))][table %s: %s]] %s\n"
902                      c-b start counter (or name "") caption)
903                   (format
904                    "[[elisp:(progn (switch-to-buffer \"%s\")(widen)(goto-char %s))][table %s: %s]]\n"
905                    c-b start counter (or name ""))))))))
906     (switch-to-buffer "*List of Tables*")
907     (setq buffer-read-only nil)
908     (org-mode)
909     (erase-buffer)
910     (insert (mapconcat 'identity list-of-tables ""))
911     (setq buffer-read-only t)
912     (use-local-map (copy-keymap org-mode-map))
913     (local-set-key "q" #'(lambda () (interactive) (kill-buffer))))))
914
915 (org-add-link-type
916  "list-of-tables"
917  'org-ref-list-of-tables
918  (lambda (keyword desc format)
919    (cond
920     ((eq format 'latex)
921      (format "\\listoftables")))))
922
923
924 ;; ** label link
925 (defun org-ref-count-labels (label)
926   "Counts number of matches for LABEL in the document."
927   (+ (count-matches (format "label:%s\\b[^-:]" label) (point-min) (point-max))
928      ;; for tblname, it is not enough to get word boundary
929      ;; tab-little and tab-little-2 match then.
930      (count-matches (format "^#\\+tblname:\\s-*%s\\b[^-:]" label) (point-min) (point-max))
931      (count-matches (format "\\label{%s}" label) (point-min) (point-max))
932      ;; this is the org-format #+label:
933      (count-matches (format "^#\\+label:\\s-*%s\\b[^-:]" label) (point-min) (point-max))
934      (let ((custom-id-count 0))
935        (org-map-entries
936         (lambda ()
937           (when (string= label (org-entry-get (point) "CUSTOM_ID"))
938             (setq custom-id-count (+ 1 custom-id-count)))))
939        custom-id-count)))
940
941 (org-add-link-type
942  "label"
943  (lambda (label)
944    "on clicking count the number of label tags used in the buffer. A number greater than one means multiple labels!"
945    (let ((count (org-ref-count-labels label)))
946    (message (format "%s occurence%s"
947                     count
948                     (if (or (= count 0)
949                               (> count 1))
950                         "s"
951                       ""))
952                     (org-ref-count-labels label))))
953  (lambda (keyword desc format)
954    (cond
955     ((eq format 'html) (format "(<label>%s</label>)" path))
956     ((eq format 'latex)
957      (format "\\label{%s}" keyword)))))
958
959 (defun org-label-store-link ()
960   "Store a link to a label.  The output will be a ref to that label."
961   ;; First we have to make sure we are on a label link.
962   (let* ((object (org-element-context)))
963     (when (and (equal (org-element-type object) 'link)
964                (equal (org-element-property :type object) "label"))
965       (org-store-link-props
966        :type "ref"
967        :link (concat "ref:" (org-element-property :path object))))
968
969     ;; Store link on table
970     (when (equal (org-element-type object) 'table)
971       (org-store-link-props
972        :type "ref"
973        :link (concat "ref:" (org-element-property :name object))))
974
975     ;; store link on heading with custom_id
976     ;; this is not a ref link, but it is still what you want
977     (when (and (equal (org-element-type object) 'headline)
978                (org-entry-get (point) "CUSTOM_ID"))
979       (org-store-link-props
980        :type "custom_id"
981        :link (format "[[#%s]]" (org-entry-get (point) "CUSTOM_ID"))))
982
983     ;; and to #+label: lines
984
985     (when (and (equal (org-element-type object) 'paragraph)
986                (org-element-property :name object))
987       (org-store-link-props
988        :type "ref"
989        :link (concat "ref:" (org-element-property :name object))))))
990
991 (add-hook 'org-store-link-functions 'org-label-store-link)
992
993 ;; ** ref link
994 (org-add-link-type
995  "ref"
996  (lambda (label)
997    "on clicking goto the label. Navigate back with C-c &"
998    (org-mark-ring-push)
999    ;; next search from beginning of the buffer
1000    ;; it is possible you would not find the label if narrowing is in effect
1001    (widen)
1002    (unless
1003        (or
1004         ;; our label links
1005         (progn
1006           (goto-char (point-min))
1007           (re-search-forward (format "label:%s\\b" label) nil t))
1008
1009         ;; a latex label
1010         (progn
1011           (goto-char (point-min))
1012           (re-search-forward (format "\\label{%s}" label) nil t))
1013
1014         ;; #+label: name  org-definition
1015         (progn
1016           (goto-char (point-min))
1017           (re-search-forward
1018            (format "^#\\+label:\\s-*\\(%s\\)\\b" label) nil t))
1019
1020         ;; org tblname
1021         (progn
1022           (goto-char (point-min))
1023           (re-search-forward
1024            (format "^#\\+tblname:\\s-*\\(%s\\)\\b" label) nil t)))
1025
1026      ;; we did not find anything, so go back to where we came
1027      (org-mark-ring-goto)
1028      (error "%s not found" label))
1029    (org-show-entry)
1030    (message "go back with (org-mark-ring-goto) `C-c &`"))
1031  ;formatting
1032  (lambda (keyword desc format)
1033    (cond
1034     ((eq format 'html) (format "(<ref>%s</ref>)" path))
1035     ((eq format 'latex)
1036      (format "\\ref{%s}" keyword)))))
1037
1038
1039 (defun org-ref-get-org-labels ()
1040  "Return a list of #+LABEL: labels."
1041   (save-excursion
1042     (goto-char (point-min))
1043     (let ((matches '()))
1044       (while (re-search-forward "^#\\+label:\\s-+\\(.*\\)\\b" (point-max) t)
1045         ;; do not do this for tables. We get those in `org-ref-get-tblnames'.
1046         ;; who would have thought you have save match data here? Trust me. When
1047         ;; I wrote this, you did.
1048         (unless (save-match-data  (equal (car (org-element-at-point)) 'table))
1049           (add-to-list 'matches (match-string-no-properties 1) t)))
1050       matches)))
1051
1052
1053 (defun org-ref-get-custom-ids ()
1054  "Return a list of custom_id properties in the buffer."
1055  (let ((results '()) custom_id)
1056    (org-map-entries
1057     (lambda ()
1058       (let ((custom_id (org-entry-get (point) "CUSTOM_ID")))
1059         (when (not (null custom_id))
1060           (setq results (append results (list custom_id)))))))
1061    results))
1062
1063
1064 (defun org-ref-get-latex-labels ()
1065   "Return list of matchin LaTeX defined labels in buffer."
1066   (save-excursion
1067     (goto-char (point-min))
1068     (let ((matches '()))
1069       (while (re-search-forward "\\\\label{\\([a-zA-z0-9:-]*\\)}" (point-max) t)
1070         (add-to-list 'matches (match-string-no-properties 1) t))
1071       matches)))
1072
1073
1074 (defun org-ref-get-tblnames ()
1075   "Return list of table names in the buffer."
1076   (org-element-map (org-element-parse-buffer 'element) 'table
1077     (lambda (table)
1078       (org-element-property :name table))))
1079
1080
1081 (defun org-ref-get-labels ()
1082   "Return a list of labels in the buffer that you can make a ref link to.
1083 This is used to complete ref links and in helm menus."
1084   (save-excursion
1085     (save-restriction
1086       (widen)
1087       (goto-char (point-min))
1088       (let ((matches '()))
1089         ;; these are the org-ref label:stuff  kinds
1090         (while (re-search-forward
1091                 "[^#+]label:\\([a-zA-z0-9:-]*\\)" (point-max) t)
1092           (add-to-list 'matches (match-string-no-properties 1) t))
1093         ;; now add all the other kinds of labels.
1094         (append matches
1095                 ;; #+label:
1096                 (org-ref-get-org-labels)
1097                 ;; \label{}
1098                 (org-ref-get-latex-labels)
1099                 ;; #+tblname: and actually #+label
1100                 (org-ref-get-tblnames)
1101                 ;; CUSTOM_IDs
1102                 (org-ref-get-custom-ids))))))
1103
1104
1105 (defun org-ref-helm-insert-label-link ()
1106   "Insert a label link. helm just shows you what labels already exist.
1107 If you are on a label link, replace it."
1108   (interactive)
1109   (let* ((labels (org-ref-get-labels))
1110          (cb (current-buffer)))
1111     (helm :sources `(((name . "Existing labels")
1112                       (candidates . ,labels)
1113                       ;; default action is to open to the label
1114                       (action . (lambda (label)
1115                                   ;; unfortunately I do not have markers here
1116                                   (org-open-link-from-string
1117                                    (format "ref:%s" label))))
1118                       ;; if you select a label, replace current one
1119                       (action . (lambda (label)
1120                                   (switch-to-buffer ,cb)
1121                                   (cond
1122                                    ;;  no prefix or on a link
1123                                    ((equal helm-current-prefix-arg nil)
1124                                     (let* ((object (org-element-context))
1125                                            (last-char (save-excursion
1126                                                         (goto-char (org-element-property :end object))
1127                                                         (backward-char)
1128                                                         (if (looking-at " ")
1129                                                             " "
1130                                                           ""))))
1131                                       (when (-contains? '("label")
1132                                                         (org-element-property :type object))
1133                                           ;; we are on a link, so replace it.
1134                                         (setf
1135                                            (buffer-substring
1136                                             (org-element-property :begin object)
1137                                             (org-element-property :end object))
1138                                            (concat
1139                                             (replace-regexp-in-string
1140                                              (org-element-property :path object)
1141                                              label
1142                                              (org-element-property :raw-link object))
1143                                             last-char)))))
1144                                    ;; no prefix options defined
1145                                    ))))
1146                      ;; no matching selection creates a new label
1147                      ((name . "Create new label")
1148                       (dummy)
1149                       ;; default action creates a new label, or replaces old one
1150                       (action .  (lambda (label)
1151                                    (switch-to-buffer ,cb)
1152                                    (let* ((object (org-element-context))
1153                                           (last-char (save-excursion
1154                                                        (goto-char (org-element-property :end object))
1155                                                        (backward-char)
1156                                                        (if (looking-at " ")
1157                                                            " "
1158                                                          ""))))
1159                                      (if (-contains? '("label")
1160                                                      (org-element-property :type object))
1161                                          ;; we are on a link, so replace it.
1162                                          (setf
1163                                           (buffer-substring
1164                                            (org-element-property :begin object)
1165                                            (org-element-property :end object))
1166                                           (concat
1167                                            (replace-regexp-in-string
1168                                             (org-element-property :path object)
1169                                             helm-pattern
1170                                             (org-element-property :raw-link object))
1171                                            last-char))
1172                                        ;; new link
1173                                        (insert
1174                                         (concat
1175                                          "label:"
1176                                          (or label
1177                                              helm-pattern))))))))))))
1178
1179
1180 (defun org-ref-complete-link (&optional arg)
1181   "Completion function for ref links.
1182 Optional argument ARG Does nothing."
1183   (let ((label))
1184     (setq label (completing-read "label: " (org-ref-get-labels)))
1185     (format "ref:%s" label)))
1186
1187
1188 (defun org-ref-insert-ref-link ()
1189   "Completion function for a ref link."
1190  (interactive)
1191  (insert (org-ref-complete-link)))
1192
1193
1194 (defun org-ref-helm-insert-ref-link ()
1195   "Helm menu to insert ref links to labels in the document.
1196 If you are on link, replace with newly selected label.
1197 Use C-u to insert a different kind of ref link.
1198 Use C-u C-u to insert a [[#custom-id]] link"
1199   (interactive)
1200   (let* ((labels (org-ref-get-labels))
1201          (bs (buffer-string))
1202          (contexts (with-temp-buffer
1203                      (insert bs)
1204                      (mapcar 'org-ref-get-label-context labels)))
1205          (cb (current-buffer)))
1206
1207     (helm :input (thing-at-point 'word)
1208           :sources `(((name . "Available labels to ref")
1209                       (candidates . ,(loop for label in labels
1210                                            for context in contexts
1211                                            ;; we do some kludgy adding spaces
1212                                            ;; and bars to make it "easier" to
1213                                            ;; see in helm.
1214                                            collect (cons (concat
1215                                                           label "\n"
1216                                                           (mapconcat
1217                                                            (lambda (x)
1218                                                              (concat "   |" x))
1219                                                            (split-string context "\n")
1220                                                            "\n"
1221                                                            ) "\n\n") label)))
1222                       ;; default action to replace or insert ref link.
1223                       (action . (lambda (label)
1224                                   (switch-to-buffer ,cb)
1225
1226                                   (cond
1227                                    ;;  no prefix or on a link
1228                                    ((equal helm-current-prefix-arg nil)
1229                                     (let* ((object (org-element-context))
1230                                            (last-char (save-excursion
1231                                                         (goto-char (org-element-property :end object))
1232                                                         (backward-char)
1233                                                         (if (looking-at " ")
1234                                                             " "
1235                                                           ""))))
1236                                       (if (-contains? '("ref" "eqref" "pageref" "nameref")
1237                                                       (org-element-property :type object))
1238                                           ;; we are on a link, so replace it.
1239                                           (setf
1240                                            (buffer-substring
1241                                             (org-element-property :begin object)
1242                                             (org-element-property :end object))
1243                                            (concat
1244                                             (replace-regexp-in-string
1245                                              (org-element-property :path object)
1246                                              label
1247                                              (org-element-property :raw-link object))
1248                                             last-char))
1249                                         ;; insert a new link
1250                                         (insert
1251                                          (concat
1252                                           "ref:" label))
1253                                         )))
1254                                    ;; one prefix, alternate ref link
1255                                    ((equal helm-current-prefix-arg '(4))
1256                                     (insert
1257                                      (concat
1258                                       (helm :sources '((name . "Ref link types")
1259                                                        (candidates . ("ref" "eqref" "pageref" "nameref"))
1260                                                        (action . (lambda (x) x))))
1261                                       ":" label)))
1262                                    ;; two prefixes, insert section custom-id link
1263                                    ((equal helm-current-prefix-arg '(16))
1264                                     (insert
1265                                      (format "[[#%s]]" label)))
1266                                    ))
1267                               ))))))
1268
1269 ;; *** pageref link
1270 (org-add-link-type
1271  "pageref"
1272  (lambda (label)
1273    "on clicking goto the label. Navigate back with C-c &"
1274    (org-mark-ring-push)
1275    ;; next search from beginning of the buffer
1276    (widen)
1277    (unless
1278        (or
1279         ;; our label links
1280         (progn
1281           (goto-char (point-min))
1282           (re-search-forward (format "label:%s\\b" label) nil t))
1283
1284         ;; a latex label
1285         (progn
1286           (goto-char (point-min))
1287           (re-search-forward (format "\\label{%s}" label) nil t))
1288
1289         ;; #+label: name  org-definition
1290         (progn
1291           (goto-char (point-min))
1292           (re-search-forward
1293            (format "^#\\+label:\\s-*\\(%s\\)\\b" label) nil t))
1294
1295         ;; org tblname
1296         (progn
1297           (goto-char (point-min))
1298           (re-search-forward
1299            (format "^#\\+tblname:\\s-*\\(%s\\)\\b" label) nil t)))
1300      ;; we did not find anything, so go back to where we came
1301      (org-mark-ring-goto)
1302      (error "%s not found" label))
1303    (message "go back with (org-mark-ring-goto) `C-c &`"))
1304  ;formatting
1305  (lambda (keyword desc format)
1306    (cond
1307     ((eq format 'html) (format "(<pageref>%s</pageref>)" path))
1308     ((eq format 'latex)
1309      (format "\\pageref{%s}" keyword)))))
1310
1311
1312 (defun org-pageref-complete-link (&optional arg)
1313   "Completion function for ref links.
1314 Optional argument ARG Does nothing."
1315   (let ((label))
1316     (setq label (completing-read "label: " (org-ref-get-labels)))
1317     (format "ref:%s" label)))
1318
1319
1320 (defun org-pageref-insert-ref-link ()
1321   "Insert a pageref link with completion."
1322  (interactive)
1323  (insert (org-pageref-complete-link)))
1324
1325
1326 ;; *** nameref link
1327 (org-add-link-type
1328  "nameref"
1329  (lambda (label)
1330    "on clicking goto the label. Navigate back with C-c &"
1331    (org-mark-ring-push)
1332    ;; next search from beginning of the buffer
1333    (widen)
1334    (unless
1335        (or
1336         ;; a latex label
1337         (progn
1338           (goto-char (point-min))
1339           (re-search-forward (format "\\label{%s}" label) nil t))
1340         )
1341      ;; we did not find anything, so go back to where we came
1342      (org-mark-ring-goto)
1343      (error "%s not found" label))
1344    (message "go back with (org-mark-ring-goto) `C-c &`"))
1345  ;formatting
1346  (lambda (keyword desc format)
1347    (cond
1348     ((eq format 'html) (format "(<nameref>%s</nameref>)" path))
1349     ((eq format 'latex)
1350      (format "\\nameref{%s}" keyword)))))
1351
1352 ;; *** eqref link
1353
1354 (org-add-link-type
1355  "eqref"
1356  (lambda (label)
1357    "on clicking goto the label. Navigate back with C-c &"
1358    (org-mark-ring-push)
1359    ;; next search from beginning of the buffer
1360    (widen)
1361    (goto-char (point-min))
1362    (unless
1363        (or
1364         ;; search forward for the first match
1365         ;; our label links
1366         (re-search-forward (format "label:%s" label) nil t)
1367         ;; a latex label
1368         (re-search-forward (format "\\label{%s}" label) nil t)
1369         ;; #+label: name  org-definition
1370         (re-search-forward (format "^#\\+label:\\s-*\\(%s\\)\\b" label) nil t))
1371      (org-mark-ring-goto)
1372      (error "%s not found" label))
1373    (message "go back with (org-mark-ring-goto) `C-c &`"))
1374  ;formatting
1375  (lambda (keyword desc format)
1376    (cond
1377     ((eq format 'html) (format "(<eqref>%s</eqref>)" path))
1378     ((eq format 'latex)
1379      (format "\\eqref{%s}" keyword)))))
1380
1381 ;; ** cite link
1382
1383 (defun org-ref-get-bibtex-key-under-cursor ()
1384   "Return key under the bibtex cursor.
1385 We search forward from
1386 point to get a comma, or the end of the link, and then backwards
1387 to get a comma, or the beginning of the link.  that delimits the
1388 keyword we clicked on.  We also strip the text properties."
1389   (let* ((object (org-element-context))
1390          (link-string (org-element-property :path object)))
1391     ;; you may click on the part before the citations. here we make
1392     ;; sure to move to the beginning so you get the first citation.
1393     (let ((cp (point)))
1394       (goto-char (org-element-property :begin object))
1395       (search-forward link-string (org-element-property :end object))
1396       (goto-char (match-beginning 0))
1397       ;; check if we clicked before the path and move as needed.
1398       (unless (< cp (point))
1399         (goto-char cp)))
1400
1401     (if (not (org-element-property :contents-begin object))
1402         ;; this means no description in the link
1403         (progn
1404           ;; we need the link path start and end
1405           (save-excursion
1406             (goto-char (org-element-property :begin object))
1407             (search-forward link-string nil nil 1)
1408             (setq link-string-beginning (match-beginning 0))
1409             (setq link-string-end (match-end 0)))
1410
1411           ;; The key is the text between commas, or the link boundaries
1412           (save-excursion
1413             (if (search-forward "," link-string-end t 1)
1414                 (setq key-end (- (match-end 0) 1)) ; we found a match
1415               (setq key-end link-string-end))) ; no comma found so take the end
1416           ;; and backward to previous comma from point which defines the start character
1417           (save-excursion
1418             (if (search-backward "," link-string-beginning 1 1)
1419                 (setq key-beginning (+ (match-beginning 0) 1)) ; we found a match
1420               (setq key-beginning link-string-beginning))) ; no match found
1421           ;; save the key we clicked on.
1422           (setq bibtex-key
1423                 (org-ref-strip-string
1424                  (buffer-substring key-beginning key-end)))
1425           (set-text-properties 0 (length bibtex-key) nil bibtex-key)
1426           bibtex-key)
1427       ;; link with description. assume only one key
1428       link-string)))
1429
1430 (defun org-ref-find-bibliography ()
1431   "Find the bibliography in the buffer.
1432 This function sets and returns cite-bibliography-files, which is a list of files
1433 either from bibliography:f1.bib,f2.bib
1434 \bibliography{f1,f2}
1435 internal bibliographies
1436
1437 falling back to what the user has set in `org-ref-default-bibliography'"
1438   (catch 'result
1439     (save-excursion
1440       (goto-char (point-min))
1441       ;;  look for a bibliography link
1442       (when (re-search-forward "\\<bibliography:\\([^\]\|\n]+\\)" nil t)
1443         (setq org-ref-bibliography-files
1444               (mapcar 'org-ref-strip-string (split-string (match-string 1) ",")))
1445         (throw 'result org-ref-bibliography-files))
1446
1447
1448       ;; we did not find a bibliography link. now look for \bibliography
1449       (goto-char (point-min))
1450       (when (re-search-forward "\\\\bibliography{\\([^}]+\\)}" nil t)
1451         ;; split, and add .bib to each file
1452         (setq org-ref-bibliography-files
1453               (mapcar (lambda (x) (concat x ".bib"))
1454                       (mapcar 'org-ref-strip-string
1455                               (split-string (match-string 1) ","))))
1456         (throw 'result org-ref-bibliography-files))
1457
1458       ;; no bibliography found. maybe we need a biblatex addbibresource
1459       (goto-char (point-min))
1460       ;;  look for a bibliography link
1461       (when (re-search-forward "addbibresource:\\([^\]\|\n]+\\)" nil t)
1462         (setq org-ref-bibliography-files
1463               (mapcar 'org-ref-strip-string (split-string (match-string 1) ",")))
1464         (throw 'result org-ref-bibliography-files))
1465
1466       ;; we did not find anything. use defaults
1467       (setq org-ref-bibliography-files org-ref-default-bibliography)))
1468
1469     ;; set reftex-default-bibliography so we can search
1470     (set (make-local-variable 'reftex-default-bibliography) org-ref-bibliography-files)
1471     org-ref-bibliography-files)
1472
1473 (defun org-ref-key-in-file-p (key filename)
1474   "Determine if the KEY is in the FILENAME."
1475   (save-current-buffer
1476     (let ((bibtex-files (list filename)))
1477       ;; This is something I am trying because when the bibtex file is open, and
1478       ;; you have added to it, the only way I find to get the update to update
1479       ;; is to close it and reopen it. or to save it and revert it.
1480       (when (get-file-buffer filename)
1481         (set-buffer (get-file-buffer filename))
1482         (save-buffer)
1483         (revert-buffer t t))
1484       (bibtex-search-entry key t))))
1485
1486 (defun org-ref-get-bibtex-key-and-file (&optional key)
1487   "Return the bibtex KEY and file that it is in.  If no key is provided, get one under point."
1488  (let ((org-ref-bibliography-files (org-ref-find-bibliography))
1489        (file))
1490    (unless key
1491      (setq key (org-ref-get-bibtex-key-under-cursor)))
1492    (setq file     (catch 'result
1493                     (loop for file in org-ref-bibliography-files do
1494                           (if (org-ref-key-in-file-p key (file-truename file))
1495                               (throw 'result file)))))
1496    (cons key file)))
1497
1498 ;; *** key at point functions
1499
1500 (defun org-ref-open-pdf-at-point ()
1501   "Open the pdf for bibtex key under point if it exists."
1502   (interactive)
1503   (let* ((results (org-ref-get-bibtex-key-and-file))
1504          (key (car results))
1505          (pdf-file (format (concat org-ref-pdf-directory "%s.pdf") key)))
1506     (if (file-exists-p pdf-file)
1507         (org-open-file pdf-file)
1508 (message "no pdf found for %s" key))))
1509
1510
1511 (defun org-ref-open-url-at-point ()
1512   "Open the url for bibtex key under point."
1513   (interactive)
1514   (let* ((results (org-ref-get-bibtex-key-and-file))
1515          (key (car results))
1516          (bibfile (cdr results)))
1517     (save-excursion
1518       (with-temp-buffer
1519         (insert-file-contents bibfile)
1520         (bibtex-search-entry key)
1521         ;; I like this better than bibtex-url which does not always find
1522         ;; the urls
1523         (catch 'done
1524           (let ((url (bibtex-autokey-get-field "url")))
1525             (when  url
1526               (browse-url (s-trim url))
1527               (throw 'done nil)))
1528
1529           (let ((doi (bibtex-autokey-get-field "doi")))
1530             (when doi
1531               (if (string-match "^http" doi)
1532                   (browse-url doi)
1533                 (browse-url (format "http://dx.doi.org/%s" (s-trim doi))))
1534               (throw 'done nil))))))))
1535
1536
1537 (defun org-ref-open-notes-at-point ()
1538   "Open the notes for bibtex key under point."
1539   (interactive)
1540   (let* ((results (org-ref-get-bibtex-key-and-file))
1541          (key (car results))
1542          (bibfile (cdr results)))
1543     (save-excursion
1544       (with-temp-buffer
1545         (insert-file-contents bibfile)
1546         (bibtex-search-entry key)
1547         (org-ref-open-bibtex-notes)))))
1548
1549
1550 (defun org-ref-citation-at-point ()
1551   "Give message of current citation at point."
1552   (interactive)
1553   (let* ((cb (current-buffer))
1554         (results (org-ref-get-bibtex-key-and-file))
1555         (key (car results))
1556         (bibfile (cdr results)))
1557     (message "%s" (progn
1558                     (with-temp-buffer
1559                       (insert-file-contents bibfile)
1560                       (bibtex-search-entry key)
1561                       (org-ref-bib-citation))))))
1562
1563
1564 (defun org-ref-open-citation-at-point ()
1565   "Open bibtex file to key at point."
1566   (interactive)
1567   (let* ((cb (current-buffer))
1568         (results (org-ref-get-bibtex-key-and-file))
1569         (key (car results))
1570         (bibfile (cdr results)))
1571     (find-file bibfile)
1572     (bibtex-search-entry key)))
1573
1574 ;; *** cite menu
1575
1576 (defvar org-ref-cite-menu-funcs '()
1577  "Functions to run on cite click menu.
1578 Each entry is a list of (key menu-name function).
1579 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.")
1580
1581
1582 (defvar org-ref-user-cite-menu-funcs
1583   '(("C" "rossref" org-ref-crossref-at-point)
1584     ("y" "Copy entry to file" org-ref-copy-entry-at-point-to-file)
1585     ("s" "Copy summary" org-ref-copy-entry-as-summary))
1586   "User-defined functions to run on bibtex key at point.")
1587
1588
1589 (defun org-ref-copy-entry-as-summary ()
1590   "Copy the bibtex entry for the citation at point as a summary."
1591   (interactive)
1592     (save-window-excursion
1593       (org-ref-open-citation-at-point)
1594       (kill-new (org-ref-bib-citation))))
1595
1596
1597 (defun org-ref-copy-entry-at-point-to-file ()
1598   "Copy the bibtex entry for the citation at point to NEW-FILE.
1599 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."
1600   (interactive)
1601   (let ((new-file (ido-completing-read
1602                    "Copy to bibfile: "
1603                    (append org-ref-default-bibliography
1604                            (f-entries "." (lambda (f) (f-ext? f "bib"))))))
1605         (key (org-ref-get-bibtex-key-under-cursor)))
1606     (save-window-excursion
1607       (org-ref-open-citation-at-point)
1608       (bibtex-copy-entry-as-kill))
1609
1610     (let ((bibtex-files (list (file-truename new-file))))
1611       (if (assoc key (bibtex-global-key-alist))
1612           (message "That key already exists in %s" new-file)
1613         ;; add to file
1614         (save-window-excursion
1615           (find-file new-file)
1616           (goto-char (point-max))
1617           ;; make sure we are at the beginning of a line.
1618           (unless (looking-at "^") (insert "\n\n"))
1619           (bibtex-yank)
1620           (save-buffer))))))
1621
1622
1623 (defun org-ref-get-doi-at-point ()
1624   "Get doi for key at point."
1625   (let* ((results (org-ref-get-bibtex-key-and-file))
1626          (key (car results))
1627          (bibfile (cdr results))
1628          doi)
1629     (save-excursion
1630       (with-temp-buffer
1631         (insert-file-contents bibfile)
1632         (bibtex-search-entry key)
1633         (setq doi (bibtex-autokey-get-field "doi"))
1634         ;; in case doi is a url, remove the url part.
1635         (replace-regexp-in-string "^http://dx.doi.org/" "" doi)))))
1636
1637
1638 ;; **** functions that operate on key at point for click menu
1639 (defun org-ref-wos-at-point ()
1640   "Open the doi in wos for bibtex key under point."
1641   (interactive)
1642   (doi-utils-wos (org-ref-get-doi-at-point)))
1643
1644
1645 (defun org-ref-wos-citing-at-point ()
1646   "Open the doi in wos citing articles for bibtex key under point."
1647   (interactive)
1648   (doi-utils-wos-citing (org-ref-get-doi-at-point)))
1649
1650
1651 (defun org-ref-wos-related-at-point ()
1652   "Open the doi in wos related articles for bibtex key under point."
1653   (interactive)
1654   (doi-utils-wos-related (org-ref-get-doi-at-point)))
1655
1656
1657 (defun org-ref-google-scholar-at-point ()
1658   "Open the doi in google scholar for bibtex key under point."
1659   (interactive)
1660   (doi-utils-google-scholar (org-ref-get-doi-at-point)))
1661
1662
1663 (defun org-ref-pubmed-at-point ()
1664   "Open the doi in pubmed for bibtex key under point."
1665   (interactive)
1666   (doi-utils-pubmed (org-ref-get-doi-at-point)))
1667
1668
1669 (defun org-ref-crossref-at-point ()
1670   "Open the doi in crossref for bibtex key under point."
1671   (interactive)
1672   (doi-utils-crossref (org-ref-get-doi-at-point)))
1673
1674 ;; *** Minibuffer menu
1675
1676 (defun org-ref-cite-onclick-minibuffer-menu (&optional link-string)
1677   "Action when a cite link is clicked on.
1678 Provides a menu of context sensitive actions.  If the bibtex entry
1679 has a pdf, you get an option to open it.  If there is a doi, you
1680 get a lot of options.  LINK-STRING is used by the link function."
1681   (interactive)
1682   (let* ((results (org-ref-get-bibtex-key-and-file))
1683          (key (car results))
1684          (pdf-file (format (concat org-ref-pdf-directory "%s.pdf") key))
1685          (bibfile (cdr results))
1686          (url (save-excursion
1687                 (with-temp-buffer
1688                   (insert-file-contents bibfile)
1689                   (bibtex-search-entry key)
1690                   (bibtex-autokey-get-field "url"))))
1691          (doi (save-excursion
1692                 (with-temp-buffer
1693                   (insert-file-contents bibfile)
1694                   (bibtex-search-entry key)
1695                   ;; I like this better than bibtex-url which does not always find
1696                   ;; the urls
1697                   (bibtex-autokey-get-field "doi")))))
1698
1699     (when (string= "" doi) (setq doi nil))
1700     (when (string= "" url) (setq url nil))
1701     (setq org-ref-cite-menu-funcs '())
1702
1703     ;; open action
1704     (when
1705         bibfile
1706       (add-to-list
1707        'org-ref-cite-menu-funcs
1708        '("o" "pen" org-ref-open-citation-at-point)))
1709
1710     ;; pdf
1711     (when (file-exists-p pdf-file)
1712       (add-to-list
1713        'org-ref-cite-menu-funcs
1714        `("p" "df" ,org-ref-open-pdf-function) t))
1715
1716     ;; notes
1717     (add-to-list
1718      'org-ref-cite-menu-funcs
1719      '("n" "otes" org-ref-open-notes-at-point) t)
1720
1721     ;; url
1722     (when (or url doi)
1723       (add-to-list
1724        'org-ref-cite-menu-funcs
1725        '("u" "rl" org-ref-open-url-at-point) t))
1726
1727     ;; doi funcs
1728     (when doi
1729       (add-to-list
1730        'org-ref-cite-menu-funcs
1731        '("w" "os" org-ref-wos-at-point) t)
1732
1733       (add-to-list
1734        'org-ref-cite-menu-funcs
1735        '("c" "iting" org-ref-wos-citing-at-point) t)
1736
1737       (add-to-list
1738        'org-ref-cite-menu-funcs
1739        '("r" "elated" org-ref-wos-related-at-point) t)
1740
1741       (add-to-list
1742        'org-ref-cite-menu-funcs
1743        '("g" "oogle scholar" org-ref-google-scholar-at-point) t)
1744
1745       (add-to-list
1746        'org-ref-cite-menu-funcs
1747        '("P" "ubmed" org-ref-pubmed-at-point) t))
1748
1749     ;; add user functions
1750     (dolist (tup org-ref-user-cite-menu-funcs)
1751       (add-to-list
1752        'org-ref-cite-menu-funcs
1753        tup t))
1754
1755     ;; finally quit
1756     (add-to-list
1757      'org-ref-cite-menu-funcs
1758      '("q" "uit" (lambda ())) t)
1759
1760     ;; now we make a menu
1761     ;; construct menu string as a message
1762     (message
1763      (concat
1764       (let* ((results (org-ref-get-bibtex-key-and-file))
1765              (key (car results))
1766              (bibfile (cdr results)))
1767         (save-excursion
1768           (with-temp-buffer
1769             (insert-file-contents bibfile)
1770             (bibtex-search-entry key)
1771             (org-ref-bib-citation))))
1772       "\n"
1773       (mapconcat
1774        (lambda (tup)
1775          (concat "[" (elt tup 0) "]"
1776                  (elt tup 1) " "))
1777        org-ref-cite-menu-funcs "")))
1778     ;; get the input
1779     (let* ((input (read-char-exclusive))
1780            (choice (assoc
1781                     (char-to-string input) org-ref-cite-menu-funcs)))
1782       ;; now run the function (2nd element in choice)
1783       (when choice
1784         (funcall
1785          (elt
1786           choice
1787           2))))))
1788
1789 ;; *** Generation of the cite links
1790 (defmacro org-ref-make-completion-function (type)
1791   "Macro to make a link completion function for a link of TYPE."
1792   `(defun ,(intern (format "org-%s-complete-link" type)) (&optional arg)
1793      (interactive)
1794      (format "%s:%s"
1795              ,type
1796              (completing-read
1797               "bibtex key: "
1798               (let ((bibtex-files (org-ref-find-bibliography)))
1799                 (bibtex-global-key-alist))))))
1800
1801 (defmacro org-ref-make-format-function (type)
1802   "Macro to make a format function for a link of TYPE."
1803   `(defun ,(intern (format "org-ref-format-%s" type)) (keyword desc format)
1804      (cond
1805       ((eq format 'org)
1806        (mapconcat
1807         (lambda (key)
1808           (format "[[#%s][%s]]" key key))
1809         (org-ref-split-and-strip-string keyword) ","))
1810
1811       ((eq format 'ascii)
1812        (concat "["
1813                (mapconcat
1814                 (lambda (key)
1815                   (format "%s" key))
1816                 (org-ref-split-and-strip-string keyword) ",") "]"))
1817
1818       ((eq format 'html)
1819        (mapconcat
1820         (lambda (key)
1821           (format "<a href=\"#%s\">%s</a>" key key))
1822         (org-ref-split-and-strip-string keyword) ","))
1823
1824       ((eq format 'latex)
1825        (if (string= (substring type -1) "s")
1826            ;; biblatex format for multicite commands, which all end in s. These are formated as \cites{key1}{key2}...
1827            (concat "\\" ,type (mapconcat (lambda (key) (format "{%s}"  key))
1828                                          (org-ref-split-and-strip-string keyword) ""))
1829          ;; bibtex format
1830        (concat "\\" ,type (when desc (org-ref-format-citation-description desc)) "{"
1831                (mapconcat (lambda (key) key) (org-ref-split-and-strip-string keyword) ",")
1832                "}")))
1833       ;; for markdown we generate pandoc citations
1834       ((eq format 'md)
1835        (cond
1836         (desc  ;; pre and or post text
1837          (let* ((text (split-string desc "::"))
1838                 (pre (car text))
1839                 (post (cadr text)))
1840            (concat
1841             (format "[@%s," keyword)
1842             (when pre (format " %s" pre))
1843             (when post (format ", %s" post))
1844             "]")))
1845         (t
1846          (format "[%s]"
1847                  (mapconcat
1848                   (lambda (key) (concat "@" key))
1849                   (org-ref-split-and-strip-string keyword)
1850                   "; "))))))))
1851
1852 (defun org-ref-format-citation-description (desc)
1853   "Return formatted citation description.
1854 If the cite link has a DESC (description), it is optional text
1855 for the citation command.  You can specify pre and post text by
1856 separating these with ::, for example [[cite:key][pre text::post
1857 text]]."
1858   (cond
1859    ((string-match "::" desc)
1860     (format "[%s][%s]" (car (setq results (split-string desc "::"))) (cadr results)))
1861    (t (format "[%s]" desc))))
1862
1863 (defun org-ref-define-citation-link (type &optional key)
1864   "Add a citation link of TYPE for org-ref.
1865 With optional KEY, set the reftex binding. For example:
1866 \(org-ref-define-citation-link \"citez\" ?z) will create a new
1867 citez link, with reftex key of z, and the completion function."
1868   (interactive "sCitation Type: \ncKey: ")
1869
1870   ;; create the formatting function
1871   (eval `(org-ref-make-format-function ,type))
1872
1873   (eval-expression
1874    `(org-add-link-type
1875      ,type
1876      org-ref-cite-onclick-function
1877      (quote ,(intern (format "org-ref-format-%s" type)))))
1878
1879   ;; create the completion function
1880   (eval `(org-ref-make-completion-function ,type))
1881
1882   ;; store new type so it works with adding citations, which checks
1883   ;; for existence in this list
1884   (add-to-list 'org-ref-cite-types type)
1885
1886   ;; and finally if a key is specified, we modify the reftex menu
1887   (when key
1888     (setf (nth 2 (assoc 'org reftex-cite-format-builtin))
1889           (append (nth 2 (assoc 'org reftex-cite-format-builtin))
1890                   `((,key  . ,(concat type ":%l")))))))
1891
1892 ;; create all the link types and their completion functions
1893 (mapcar 'org-ref-define-citation-link org-ref-cite-types)
1894
1895 (defun org-ref-insert-cite-link (alternative-cite)
1896   "Insert a default citation link using reftex.
1897 If you are on a link, it appends to the end of the link,
1898 otherwise, a new link is inserted.  Use a prefix
1899 arg (ALTERNATIVE-CITE) to get a menu of citation types."
1900   (interactive "P")
1901   (org-ref-find-bibliography)
1902   (let* ((object (org-element-context))
1903          (link-string-beginning (org-element-property :begin object))
1904          (link-string-end (org-element-property :end object))
1905          (path (org-element-property :path object)))
1906
1907     (if (not alternative-cite)
1908
1909         (cond
1910          ;; case where we are in a link
1911          ((and (equal (org-element-type object) 'link)
1912                (-contains? org-ref-cite-types (org-element-property :type object)))
1913           (goto-char link-string-end)
1914           ;; sometimes there are spaces at the end of the link
1915           ;; this code moves point pack until no spaces are there
1916           (while (looking-back " ") (backward-char))
1917           (insert (concat "," (mapconcat 'identity (reftex-citation t ?a) ","))))
1918
1919          ;; We are next to a link, and we want to append
1920          ((save-excursion
1921             (backward-char)
1922             (and (equal (org-element-type (org-element-context)) 'link)
1923                  (-contains? org-ref-cite-types (org-element-property :type (org-element-context)))))
1924           (while (looking-back " ") (backward-char))
1925           (insert (concat "," (mapconcat 'identity (reftex-citation t ?a) ","))))
1926
1927          ;; insert fresh link
1928          (t
1929           (insert
1930            (concat org-ref-default-citation-link
1931                    ":"
1932                    (mapconcat 'identity (reftex-citation t) ",")))))
1933
1934       ;; you pressed a C-u so we run this code
1935       (reftex-citation))))
1936
1937 (defun org-ref-insert-cite-with-completion (type)
1938   "Insert a cite link of TYPE with completion."
1939   (interactive (list (ido-completing-read "Type: " org-ref-cite-types)))
1940   (insert (funcall (intern (format "org-%s-complete-link" type)))))
1941
1942 (defun org-ref-store-bibtex-entry-link ()
1943   "Save a citation link to the current bibtex entry.  Save in the default link type."
1944   (interactive)
1945   (let ((link (concat org-ref-default-citation-link
1946                  ":"
1947                  (save-excursion
1948                    (bibtex-beginning-of-entry)
1949                    (reftex-get-bib-field "=key=" (bibtex-parse-entry))))))
1950     (message "saved %s" link)
1951     (push (list link) org-stored-links)
1952     (car org-stored-links)))
1953
1954 ;; ** Index link
1955 (org-add-link-type
1956  "index"
1957  (lambda (path)
1958    (occur path))
1959
1960  (lambda (path desc format)
1961    (cond
1962     ((eq format 'latex)
1963       (format "\\index{%s}" path)))))
1964
1965 ;; this will generate a temporary index of entries in the file.
1966 (org-add-link-type
1967  "printindex"
1968  (lambda (path)
1969    (let ((*index-links* '())
1970          (*initial-letters* '()))
1971
1972      ;; get links
1973      (org-element-map (org-element-parse-buffer) 'link
1974        (lambda (link)
1975          (let ((type (nth 0 link))
1976                (plist (nth 1 link)))
1977
1978            (when (equal (plist-get plist ':type) "index")
1979              (add-to-list
1980               '*index-links*
1981               (cons (plist-get plist :path)
1982                     (format
1983                      "[[elisp:(progn (switch-to-buffer \"%s\") (goto-char %s))][%s]]"
1984 (current-buffer)
1985                      (plist-get plist :begin)  ;; position of link
1986                      ;; grab a description
1987                      (save-excursion
1988                        (goto-char (plist-get plist :begin))
1989                        (if (thing-at-point 'sentence)
1990                            ;; get a sentence
1991                            (replace-regexp-in-string
1992                             "\n" "" (thing-at-point 'sentence))
1993                          ;; or call it a link
1994                          "link")))))))))
1995
1996      ;; sort the links
1997      (setq *index-links*  (cl-sort *index-links* 'string-lessp :key 'car))
1998
1999      ;; now first letters
2000      (dolist (link *index-links*)
2001        (add-to-list '*initial-letters* (substring (car link) 0 1) t))
2002
2003      ;; now create the index
2004      (switch-to-buffer (get-buffer-create "*index*"))
2005      (org-mode)
2006      (erase-buffer)
2007      (insert "#+TITLE: Index\n\n")
2008      (dolist (letter *initial-letters*)
2009        (insert (format "* %s\n" (upcase letter)))
2010        ;; now process the links
2011        (while (and
2012                *index-links*
2013                (string= letter (substring (car (car *index-links*)) 0 1)))
2014          (let ((link (pop *index-links*)))
2015            (insert (format "%s %s\n\n" (car link) (cdr link))))))
2016      (switch-to-buffer "*index*")))
2017  ;; formatting
2018  (lambda (path desc format)
2019    (cond
2020     ((eq format 'latex)
2021       (format "\\printindex")))))
2022
2023 ;; ** Glossary link
2024 (org-add-link-type
2025  "newglossaryentry"
2026  nil ;; no follow action
2027  (lambda (path desc format)
2028    (cond
2029     ((eq format 'latex)
2030      (format "\\newglossaryentry{%s}{%s}" path desc)))))
2031
2032
2033 ;; link to entry
2034 (org-add-link-type
2035  "gls"
2036   nil ;; no follow action
2037  (lambda (path desc format)
2038    (cond
2039     ((eq format 'latex)
2040      (format "\\gls{%s}" path)))))
2041
2042 ;; plural
2043 (org-add-link-type
2044  "glspl"
2045   nil ;; no follow action
2046  (lambda (path desc format)
2047    (cond
2048     ((eq format 'latex)
2049      (format "\\glspl{%s}" path)))))
2050
2051 ;; capitalized link
2052 (org-add-link-type
2053  "Gls"
2054   nil ;; no follow action
2055  (lambda (path desc format)
2056    (cond
2057     ((eq format 'latex)
2058      (format "\\Gls{%s}" path)))))
2059
2060 ;; capitalized link
2061 (org-add-link-type
2062  "Glspl"
2063   nil ;; no follow action
2064  (lambda (path desc format)
2065    (cond
2066     ((eq format 'latex)
2067      (format "\\Glspl{%s}" path)))))
2068
2069 ;; * Utilities
2070 ;; ** create text citations from a bibtex entry
2071 (defun org-ref-bib-citation ()
2072   "From a bibtex entry, create and return a simple citation string.
2073 This assumes you are in an article."
2074
2075   (bibtex-beginning-of-entry)
2076   (let* ((cb (current-buffer))
2077          (bibtex-expand-strings t)
2078          (entry (loop for (key . value) in (bibtex-parse-entry t)
2079                       collect (cons (downcase key) value)))
2080          (title (replace-regexp-in-string "\n\\|\t\\|\s+" " " (reftex-get-bib-field "title" entry)))
2081          (year  (reftex-get-bib-field "year" entry))
2082          (author (replace-regexp-in-string "\n\\|\t\\|\s+" " " (reftex-get-bib-field "author" entry)))
2083          (key (reftex-get-bib-field "=key=" entry))
2084          (journal (reftex-get-bib-field "journal" entry))
2085          (volume (reftex-get-bib-field "volume" entry))
2086          (pages (reftex-get-bib-field "pages" entry))
2087          (doi (reftex-get-bib-field "doi" entry))
2088          (url (reftex-get-bib-field "url" entry))
2089          )
2090     ;;authors, "title", Journal, vol(iss):pages (year).
2091     (format "%s, \"%s\", %s, %s:%s (%s)"
2092             author title journal  volume pages year)))
2093
2094 (defun org-ref-bib-html-citation ()
2095   "From a bibtex entry, create and return a simple citation with html links."
2096   (bibtex-beginning-of-entry)
2097   (let* ((cb (current-buffer))
2098          (bibtex-expand-strings t)
2099          (entry (loop for (key . value) in (bibtex-parse-entry t)
2100                       collect (cons (downcase key) value)))
2101          (title (replace-regexp-in-string "\n\\|\t\\|\s+" " " (reftex-get-bib-field "title" entry)))
2102          (year  (reftex-get-bib-field "year" entry))
2103          (author (replace-regexp-in-string "\n\\|\t\\|\s+" " " (reftex-get-bib-field "author" entry)))
2104          (key (reftex-get-bib-field "=key=" entry))
2105          (journal (reftex-get-bib-field "journal" entry))
2106          (volume (reftex-get-bib-field "volume" entry))
2107          (pages (reftex-get-bib-field "pages" entry))
2108          (doi (reftex-get-bib-field "doi" entry))
2109          (url (reftex-get-bib-field "url" entry)))
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
2115               (format " <a href=\"http://dx.doi.org/%s\">doi</a>" doi)))))
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