-** Sort entries in citation links with shift-arrow keys
-Sometimes it may be helpful to manually change the order of citations. These functions define shift-arrow functions.
-#+BEGIN_SRC emacs-lisp :tangle org-ref.el
-(defun org-ref-swap-keys (i j keys)
- "swap the keys in a list with index i and j"
- (let ((tempi (nth i keys)))
- (setf (nth i keys) (nth j keys))
- (setf (nth j keys) tempi))
- keys)
-
-(defun org-ref-swap-citation-link (direction)
- "move citation at point in direction +1 is to the right, -1 to the left"
- (interactive)
- (let* ((object (org-element-context))
- (type (org-element-property :type object))
- (begin (org-element-property :begin object))
- (end (org-element-property :end object))
- (link-string (org-element-property :path object))
- key keys i)
- ;; We only want this to work on citation links
- (when (-contains? org-ref-cite-types type)
- (setq key (org-ref-get-bibtex-key-under-cursor))
- (setq keys (org-ref-split-and-strip-string link-string))
- (setq i (index key keys)) ;; defined in org-ref
- (if (> direction 0) ;; shift right
- (org-ref-swap-keys i (+ i 1) keys)
- (org-ref-swap-keys i (- i 1) keys))
- (setq keys (mapconcat 'identity keys ","))
- ;; and replace the link with the sorted keys
- (cl--set-buffer-substring begin end (concat type ":" keys " "))
- ;; now go forward to key so we can move with the key
- (re-search-forward key)
- (goto-char (match-beginning 0)))))
-
-;; add hooks to make it work
-(add-hook 'org-shiftright-hook (lambda () (org-ref-swap-citation-link 1)))
-(add-hook 'org-shiftleft-hook (lambda () (org-ref-swap-citation-link -1)))
-#+END_SRC
-
-** Lightweight messages about links
-To get a lighter weight message about the label, ref and cite links, we define a function that gives us the minibuffer message, without the menu. We run this in an idle timer.
-
-#+BEGIN_SRC emacs-lisp :tangle org-ref.el
-(defun org-ref-get-label-context (label)
- "Return a string of context around a label."
- (save-excursion
- (catch 'result
- (goto-char (point-min))
- (when (re-search-forward
- (format "label:%s\\b" label) nil t)
- (throw 'result (buffer-substring
- (progn
- (previous-line)
- (beginning-of-line)
- (point))
- (progn
- (forward-line 4)
- (point)))))
-
- (goto-char (point-min))
- (when (re-search-forward
- (format "\\label{%s}" label) nil t)
- (throw 'result (buffer-substring
- (progn
- (previous-line)
- (beginning-of-line)
- (point))
- (progn
- (forward-line 4)
- (point)))))
-
- (goto-char (point-min))
- (when (re-search-forward
- (format "^#\\+label:\\s-*\\(%s\\)\\b" label) nil t)
- (throw 'result (buffer-substring
- (progn
- (previous-line)
- (beginning-of-line)
- (point))
- (progn
- (forward-line 4)
- (point)))))
-
- (goto-char (point-min))
- (when (re-search-forward
- (format "^#\\+tblname:\\s-*\\(%s\\)\\b" label) nil t)
- (throw 'result (buffer-substring
- (progn
- (previous-line)
- (beginning-of-line)
- (point))
- (progn
- (forward-line 4)
- (point)))))
- (throw 'result "!!! NO CONTEXT FOUND !!!"))))
-
-
-(defun org-ref-link-message ()
- "Print a minibuffer message about the link that point is on."
- (interactive)
- (when (eq major-mode 'org-mode)
- (let* ((object (org-element-context))
- (type (org-element-property :type object)))
- (save-excursion
- (cond
- ;; cite links
- ((-contains? org-ref-cite-types type)
- (message (org-ref-get-citation-string-at-point)))
-
- ;; message some context about the label we are referring to
- ((string= type "ref")
- (message "%scount: %s"
- (org-ref-get-label-context
- (org-element-property :path object))
- (org-ref-count-labels
- (org-element-property :path object))))
-
- ((string= type "eqref")
- (message "%scount: %s"
- (org-ref-get-label-context
- (org-element-property :path object))
- (org-ref-count-labels
- (org-element-property :path object))))
-
- ;; message the count
- ((string= type "label")
- (let ((count (org-ref-count-labels
- (org-element-property :path object))))
- ;; get plurality on occurrence correct
- (message (concat
- (number-to-string count)
- " occurence"
- (when (or (= count 0)
- (> count 1))
- "s")))))
-
- ((string= type "custom-id")
- (save-excursion
- (org-open-link-from-string
- (format "[[#%s]]" (org-element-property :path object)))
- (message "%s" (org-get-heading))))
-
- ;; check if the bibliography files exist.
- ((string= type "bibliography")
- (let* ((bibfile)
- ;; object is the link you clicked on
- (object (org-element-context))
- (link-string (org-element-property :path object))
- (link-string-beginning)
- (link-string-end))
- (save-excursion
- (goto-char (org-element-property :begin object))
- (search-forward link-string nil nil 1)
- (setq link-string-beginning (match-beginning 0))
- (setq link-string-end (match-end 0)))
-
- ;; make sure we are in link and not before the :
- (when (> link-string-beginning (point))
- (goto-char link-string-beginning))
-
- ;; now if we have comma separated bibliographies
- ;; we find the one clicked on. we want to
- ;; search forward to next comma from point
- (save-excursion
- (if (search-forward "," link-string-end 1 1)
- (setq key-end (- (match-end 0) 1)) ; we found a match
- (setq key-end (point)))) ; no comma found so take the point
-
- ;; and backward to previous comma from point
- (save-excursion
- (if (search-backward "," link-string-beginning 1 1)
- (setq key-beginning (+ (match-beginning 0) 1)) ; we found a match
- (setq key-beginning (point)))) ; no match found
- ;; save the key we clicked on.
- (setq bibfile
- (org-ref-strip-string
- (buffer-substring key-beginning key-end)))
- (if (file-exists-p bibfile)
- (message "%s exists." bibfile)
- (message "!!! %s NOT FOUND !!!" bibfile))))
- )))))
-#+END_SRC
-
-* Aliases
-I like convenience. Here are some aliases for faster typing.
-
-#+BEGIN_SRC emacs-lisp :tangle org-ref.el
-(defalias 'oro 'org-ref-open-citation-at-point)
-(defalias 'orc 'org-ref-citation-at-point)
-(defalias 'orp 'org-ref-open-pdf-at-point)
-(defalias 'oru 'org-ref-open-url-at-point)
-(defalias 'orn 'org-ref-open-notes-at-point)
-(defalias 'ornr 'org-ref-open-notes-from-reftex)
-
-(defalias 'orib 'org-ref-insert-bibliography-link)
-(defalias 'oric 'org-ref-insert-cite-link)
-(defalias 'orir 'org-ref-insert-ref-link)
-(defalias 'orsl 'org-ref-store-bibtex-entry-link)
-
-(defalias 'orcb 'org-ref-clean-bibtex-entry)
-#+END_SRC
-* Helm interface
-[[https://github.com/tmalsburg/helm-bibtex][helm-bibtex]] is a very cool interface to bibtex files. Out of the box though, it is not super convenient for org-ref. Here, we modify it to make it fit our workflow and extend it where needed.
-
-1. Make the default action to insert selected keys.
-2. Make open entry second action
-#+BEGIN_SRC emacs-lisp :tangle org-ref.el
-(setq helm-source-bibtex
- '((name . "BibTeX entries")
- (init . helm-bibtex-init)
- (candidates . helm-bibtex-candidates)
- (filtered-candidate-transformer . helm-bibtex-candidates-formatter)
- (action . (("Insert citation" . helm-bibtex-insert-citation)
- ("Show entry" . helm-bibtex-show-entry)
- ("Open PDF file (if present)" . helm-bibtex-open-pdf)
- ("Open URL or DOI in browser" . helm-bibtex-open-url-or-doi)
- ("Insert reference" . helm-bibtex-insert-reference)
- ("Insert BibTeX key" . helm-bibtex-insert-key)
- ("Insert BibTeX entry" . helm-bibtex-insert-bibtex)
- ("Attach PDF to email" . helm-bibtex-add-PDF-attachment)
- ("Edit notes" . helm-bibtex-edit-notes)
- ))))
-#+END_SRC
-
-Now, let us define a function that inserts the cite links:
-#+BEGIN_SRC emacs-lisp :tangle org-ref.el
-(defun helm-bibtex-format-org-ref (keys)
- "Insert selected KEYS as cite link. Append KEYS if you are on a link.
-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.
-
-In the helm-bibtex buffer, C-u will give you a helm menu to select a new link type for the selected entries.
-
-C-u C-u will change the key at point to the selected keys.
-"
- (let* ((object (org-element-context))
- (last-char (save-excursion
- (goto-char (org-element-property :end object))
- (backward-char)
- (if (looking-at " ")
- " "
- ""))))
- (cond
- ;; case where we are in a link
- ((and (equal (org-element-type object) 'link)
- (-contains?
- org-ref-cite-types
- (org-element-property :type object)))
- (cond
- ;; no prefix. append keys
- ((equal helm-current-prefix-arg nil)
- (goto-char (org-element-property :end object))
- (while (looking-back " ") (backward-char))
- (insert (concat "," (mapconcat 'identity keys ","))))
- ;; double prefix, replace key at point
- ((equal helm-current-prefix-arg '(16))
- (setf (buffer-substring
- (org-element-property :begin object)
- (org-element-property :end object))
- (concat
- (replace-regexp-in-string
- (car (org-ref-get-bibtex-key-and-file)) ; key
- (mapconcat 'identity keys ",") ; new keys
- (org-element-property :raw-link object))
- ;; replace space at end to avoid collapsing into next word.
- last-char))
- ;; and we want to go to the end of the new link
- (goto-char
- (org-element-property :end (org-element-context))))
- (t
- (message "Not found"))))
-
- ;; We are next to a link, and we want to append
- ;; next to a link means one character back is on a link.
- ((save-excursion
- (backward-char)
- (and (equal (org-element-type (org-element-context)) 'link)
- (-contains?
- org-ref-cite-types
- (org-element-property :type (org-element-context)))))
- (while (looking-back " ") (backward-char))
- (insert (concat "," (mapconcat 'identity keys ","))))
-
- ;; insert fresh link
- (t
- ;;(message-box "fresh link")
- (insert
- (concat (if (equal helm-current-prefix-arg '(4))
- (helm :sources `((name . "link types")
- (candidates . ,org-ref-cite-types)
- (action . (lambda (x) x))))
- org-ref-default-citation-link)
- ":"
- (s-join "," keys))))))
- ;; return empty string for helm
- "")
-
-(setq helm-bibtex-format-citation-functions
- '((org-mode . helm-bibtex-format-org-ref)))
-
-(defun org-ref-helm-insert-cite-link (arg)
- "org-ref function to use helm-bibtex to insert a citation link.
-With one prefix arg, insert a ref link.
-With two prefix args, insert a label link."
- (interactive "P")
- (cond
- ((equal arg nil)
- (let ((helm-bibtex-bibliography (org-ref-find-bibliography)))
- (helm-bibtex)))
- ((equal arg '(4))
- (org-ref-helm-insert-ref-link))
- ((equal arg '(16))
- (org-ref-helm-insert-label-link))))
-
-(require 'helm-bibtex)
-
-;; add our own fallback entries where we want them. These appear in reverse order of adding in the menu
-(setq helm-bibtex-fallback-options
- (-insert-at 1 '("Crossref" . "http://search.crossref.org/?q=%s") helm-bibtex-fallback-options))
-
-(setq helm-bibtex-fallback-options
- (-insert-at
- 1
- '("Scopus" . "http://www.scopus.com/scopus/search/submit/xadvanced.url?searchfield=TITLE-ABS-KEY(%s)")
- helm-bibtex-fallback-options))
-
-(setq helm-bibtex-fallback-options
- (-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))
-#+END_SRC
-
-** A helm click menu
-This code provides a helm interface to things you can do when you click on a citation link. This is an alternative to the minibuffer menu.
-#+BEGIN_SRC emacs-lisp :tangle org-ref.el
-(defun org-ref-get-citation-string-at-point ()
- "Get a string of a formatted citation"
- (interactive)
- (let* ((results (org-ref-get-bibtex-key-and-file))
- (key (car results))
- (bibfile (cdr results)))
- (if bibfile
- (save-excursion
- (with-temp-buffer
- (insert-file-contents bibfile)
- (bibtex-search-entry key)
- (org-ref-bib-citation)))
- "!!! No entry found !!!" )))
-
-(defun org-ref-cite-candidates ()
- "Generate the list of possible candidates for click actions on a cite link.
-Checks for pdf and doi, and add appropriate functions."
- (interactive)
- (let* ((results (org-ref-get-bibtex-key-and-file))
- (key (car results))
- (pdf-file (format (concat org-ref-pdf-directory "%s.pdf") key))
- (bibfile (cdr results))
- (url (save-excursion
- (with-temp-buffer
- (insert-file-contents bibfile)
- (bibtex-search-entry key)
- (bibtex-autokey-get-field "url"))))
- (doi (save-excursion
- (with-temp-buffer
- (insert-file-contents bibfile)
- (bibtex-search-entry key)
- ;; I like this better than bibtex-url which does not always find
- ;; the urls
- (bibtex-autokey-get-field "doi"))))
- (candidates `(("Quit" . org-ref-citation-at-point)
- ("Open bibtex entry" . org-ref-open-citation-at-point))))
- ;; for some reason, when there is no doi or url, they are returned as "". I
- ;; prefer nil so we correct this here.
- (when (string= doi "") (setq doi nil))
- (when (string= url "") (setq url nil))
-
- ;; Conditional pdf functions
- (if (file-exists-p pdf-file)
- (add-to-list
- 'candidates
- '("Open pdf" . org-ref-open-pdf-at-point)
- t)
- (add-to-list
- 'candidates
- '("Try to get pdf" . (lambda ()
- (save-window-excursion
- (org-ref-open-citation-at-point)
- (bibtex-beginning-of-entry)
- (doi-utils-get-bibtex-entry-pdf))))
- t))
-
-
- (add-to-list
- 'candidates
- '("Open notes" . org-ref-open-notes-at-point)
- t)
-
- ;; conditional url and doi functions
- (when (or url doi)
- (add-to-list
- 'candidates
- '("Open in browser" . org-ref-open-url-at-point)
- t))
-
- (when doi
- (mapc (lambda (x)
- (add-to-list 'candidates x t))
- `(("WOS" . org-ref-wos-at-point)
- ("Related articles in WOS" . org-ref-wos-related-at-point)
- ("Citing articles in WOS" . org-ref-wos-citing-at-point)
- ("Google Scholar" . org-ref-google-scholar-at-point)
- ("Pubmed" . org-ref-pubmed-at-point)
- ("Crossref" . org-ref-crossref-at-point)
- )))
-
- (add-to-list
- 'candidates
- '("Copy formatted citation to clipboard" . org-ref-copy-entry-as-summary)
- t)
-
- (add-to-list
- 'candidates
- '("Copy key to clipboard" . (lambda ()
- (kill-new
- (car (org-ref-get-bibtex-key-and-file)))))
- t)
-
- (add-to-list
- 'candidates
- '("Copy bibtex entry to file" . org-ref-copy-entry-at-point-to-file)
- t)
-
- (add-to-list
- 'candidates
- '("Email bibtex entry and pdf" . (lambda ()
- (save-excursion
- (org-ref-open-citation-at-point)
- (email-bibtex-entry))))
- t)
- ;; finally return a numbered list of the candidates
- (loop for i from 0
- for cell in candidates
- collect (cons (format "%2s. %s" i (car cell))
- (cdr cell)))))
-
-
-(defvar org-ref-helm-user-candidates '()
- "List of user-defined candidates to act when clicking on a cite link.
-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.
-")
-
-;; example of adding your own function
-(add-to-list
- 'org-ref-helm-user-candidates
- '("Example" . (lambda () (message-box "You did it!")))
- t)
-
-(defun org-ref-cite-click-helm (key)
- "subtle points.
-1. get name and candidates before entering helm because we need the org-buffer.
-2. switch back to the org buffer before evaluating the action. most of them need the point and buffer."
- (interactive)
- (let ((name (org-ref-get-citation-string-at-point))
- (candidates (org-ref-cite-candidates))
- (cb (current-buffer)))
-
- (helm :sources `(((name . ,name)
- (candidates . ,candidates)
- (action . (lambda (f)
- (switch-to-buffer cb)
- (funcall f))))
- ((name . "User functions")
- (candidates . ,org-ref-helm-user-candidates)
- (action . (lambda (f)
- (switch-to-buffer cb)
- (funcall f))))
- ))))
-#+END_SRC
-
-#+RESULTS:
-: org-ref-cite-click-helm
-
-* End of code
-#+BEGIN_SRC emacs-lisp :tangle org-ref.el
-(provide 'org-ref)
-#+END_SRC