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