]> git.donarmstrong.com Git - org-ref.git/blobdiff - org-ref.org
Set org-edit-src-content-indentation in org files.
[org-ref.git] / org-ref.org
index 4b814f43499dfe4435fa1cf387f76ff8322feab6..f9bc3adb7f23e64267f0ff9902e57b3f0da6d258 100644 (file)
@@ -1,3 +1,4 @@
+# -*- org-edit-src-content-indentation: 0; -*-
 #+TITLE: Org-ref - The best reference handling for org-mode
 #+AUTHOR: John Kitchin
 #+DATE: April 29, 2014
 #+TITLE: Org-ref - The best reference handling for org-mode
 #+AUTHOR: John Kitchin
 #+DATE: April 29, 2014
@@ -28,11 +29,16 @@ With helm integration (default) you can:
 
 ** Header
 #+BEGIN_SRC emacs-lisp :tangle org-ref.el
 
 ** Header
 #+BEGIN_SRC emacs-lisp :tangle org-ref.el
-;;; org-ref.el --- setup bibliography, cite, ref and label org-mode links.
+;;; org-ref.el --- cite and cross-reference in org-mode
 
 ;; Copyright(C) 2014 John Kitchin
 
 ;; Author: John Kitchin <jkitchin@andrew.cmu.edu>
 
 ;; Copyright(C) 2014 John Kitchin
 
 ;; Author: John Kitchin <jkitchin@andrew.cmu.edu>
+;; URL: https://github.com/jkitchin/org-ref
+;; Version: 0.1
+;; Keywords: org-mode, cite, ref, label
+;; Package-Requires: ((dash) (helm) (helm-bibtex))
+
 ;; This file is not currently part of GNU Emacs.
 
 ;; This program is free software; you can redistribute it and/or
 ;; This file is not currently part of GNU Emacs.
 
 ;; This program is free software; you can redistribute it and/or
@@ -52,11 +58,13 @@ With helm integration (default) you can:
 
 ;;; Commentary:
 ;;
 
 ;;; Commentary:
 ;;
-;; Lisp code to setup bibliography cite, ref and label org-mode links.  also
-;; sets up reftex and helm for org-mode citations. The links are clickable and
-;; do things that are useful. You should really read org-ref.org for details.
+;; Lisp code to setup bibliography cite, ref and label org-mode links.
+;; also sets up reftex and helm for org-mode citations. The links are
+;; clickable and do things that are useful. You should really read
+;; org-ref.org for details.
 ;;
 ;;
-;; Package-Requires: ((dash) (helm) (helm-bibtex))
+
+;;; Code:
 #+END_SRC
 
 ** requires
 #+END_SRC
 
 ** requires
@@ -66,7 +74,9 @@ The only external require is reftex-cite
 (require 'reftex-cite)
 (require 'dash)
 (require 'helm)
 (require 'reftex-cite)
 (require 'dash)
 (require 'helm)
+(require 'helm-config)
 (require 'helm-bibtex)
 (require 'helm-bibtex)
+(require 'org)
 #+END_SRC
 
 ** Custom variables
 #+END_SRC
 
 ** Custom variables
@@ -150,10 +160,11 @@ There are some variables needed later to tell this library where you store your
 
 (defcustom org-ref-cite-onclick-function
   'org-ref-cite-click-helm
 
 (defcustom org-ref-cite-onclick-function
   'org-ref-cite-click-helm
-  "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."
+  "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'."
  :type 'function
  :group 'org-ref)
 
  :type 'function
  :group 'org-ref)
 
+
 (defcustom org-ref-show-citation-on-enter t
   "If non-nil add a hook function to show the citation summary in
   the minibuffer just by putting the cursor in a link"
 (defcustom org-ref-show-citation-on-enter t
   "If non-nil add a hook function to show the citation summary in
   the minibuffer just by putting the cursor in a link"
@@ -242,26 +253,6 @@ We setup reftex here. We use a custom insert cite link function defined here: [[
   (kbd org-ref-insert-cite-key)
   org-ref-insert-cite-function)
 
   (kbd org-ref-insert-cite-key)
   org-ref-insert-cite-function)
 
-(when org-ref-show-citation-on-enter
- (setq org-ref-message-timer
-       (run-with-idle-timer 0.5 t 'org-ref-link-message)))
-
-(defun org-ref-show-link-messages ()
-  "Turn on link messages. You will see a message in the
-minibuffer when on a cite, ref or label link."
-  (interactive)
-  (setq org-ref-message-timer
-       (run-with-idle-timer 0.5 t 'org-ref-link-message))
-  )
-(defun org-ref-cancel-link-messages ()
-  "Stop showing messages in minibuffer when on a link."
-  (interactive)
-  (cancel-timer org-ref-message-timer))
-
-;; this approach caused the selected region to not be highlighted any more.
-; (add-hook 'post-command-hook 'org-ref-link-message))
-; (remove-hook 'post-command-hook 'org-ref-link-message))
-
 (add-hook 'org-mode-hook 'org-mode-reftex-setup)
 
 (eval-after-load 'reftex-vars
 (add-hook 'org-mode-hook 'org-mode-reftex-setup)
 
 (eval-after-load 'reftex-vars
@@ -297,6 +288,195 @@ You can define a new citation link like this:
 (org-ref-define-citation-link "citez" ?z)
 #+END_SRC
 
 (org-ref-define-citation-link "citez" ?z)
 #+END_SRC
 
+** Messages for link at cursor
+Here we setup code that shows you a context message for the element under the cursor when emacs is idle.
+#+BEGIN_SRC emacs-lisp :tangle org-ref.el
+(defvar org-ref-message-timer nil
+  "Variable to store the link message timer in.")
+
+
+(defun org-ref-show-link-messages ()
+  "Turn on link messages. You will see a message in the
+minibuffer when on a cite, ref or label link."
+  (interactive)
+  (or org-ref-message-timer
+      (setq org-ref-message-timer
+           (run-with-idle-timer 0.5 t 'org-ref-link-message))))
+
+
+(defun org-ref-cancel-link-messages ()
+  "Stop showing messages in minibuffer when on a link."
+  (interactive)
+  (cancel-timer org-ref-message-timer)
+  (setq org-ref-message-timer nil))
+
+
+(when org-ref-show-citation-on-enter
+  (org-ref-show-link-messages))
+
+;; this approach caused the selected region to not be highlighted any more.
+; (add-hook 'post-command-hook 'org-ref-link-message))
+; (remove-hook 'post-command-hook 'org-ref-link-message))
+#+END_SRC
+
+** Messages for context under mouse pointer
+Sometimes, when reading a document, I actually use the mouse more than the cursor. This code enables the mouse cursor to trigger a message in the minibuffer about what is under the cursor. I run this on a timer.
+
+The basic idea here is to get the mouse position, and if we can determine there is a character that (point) can move to, we move (point) and run the org-ref-link-message function. Since this runs on a timer, we store the last mouse position, and only run the function when the mouse has moved to avoid getting messages every time the timer runs.
+
+#+BEGIN_SRC emacs-lisp :tangle org-ref.el
+(defvar org-ref-last-mouse-pos nil
+ "Stores last mouse position for use in `org-ref-mouse-message'.")
+
+(defun org-ref-can-move-p ()
+  "See if a character is under the mouse. If so return the position for `goto-char'."
+  (let* ((line (cddr org-ref-last-mouse-pos))
+        (col  (cadr org-ref-last-mouse-pos)))
+    (save-excursion
+      (goto-char (window-start))
+      (forward-line line)
+      (if
+         (> (- (line-end-position) (line-beginning-position)) col)
+         (progn  (forward-char col) (point))
+       nil))))
+
+
+(defun org-ref-mouse-message ()
+  "Display message for link under mouse cursor"
+  (interactive)
+  (when (not (equal (mouse-position) org-ref-last-mouse-pos))
+    (setq org-ref-last-mouse-pos (mouse-position))
+    (let ((p (org-ref-can-move-p)))
+      (when p
+         (save-excursion
+           (goto-char p)
+           (org-ref-link-message))))))
+
+
+(defvar org-ref-message-timer-mouse nil
+  "Store mouse timer.")
+
+
+(defvar org-ref-mouse-message-interval 0.5
+  "How often to run the mouse message timer in seconds")
+
+
+(defun org-ref-mouse-messages-on ()
+  "Turn on mouse messages."
+  (interactive)
+  (or org-ref-message-timer-mouse
+      (setq org-ref-message-timer-mouse
+           (run-at-time "0.5 sec"
+                        org-ref-mouse-message-interval
+                        'org-ref-mouse-message))))
+
+
+(defun org-ref-mouse-messages-off ()
+  "Turn off mouse messages"
+  (interactive)
+  (cancel-timer org-ref-message-timer-mouse)
+  (setq org-ref-message-timer-mouse nil)
+  (message "Mouse messages are off"))
+#+END_SRC
+
+#+RESULTS:
+: org-ref-mouse-messages-off
+
+** Color-coded links
+Here we make the org-ref links a different color.
+
+citations are green
+refs are blue
+labels are black
+
+mailto:john
+
+cite:sokalski-2012-optim-ta,zhang-2011-spatial-tio2,li-2012-heter-ceram,li-2013-photoc
+
+cite*:sokalski-2012-optim-ta,zhang-2011-spatial-tio2,li-2012-heter-ceram,li-2013-photoc
+
+citenum:sokalski-2012-optim-ta,zhang-2011-spatial-tio2,li-2012-heter-ceram,li-2013-photoc
+
+ref:test
+
+label:test
+
+#+BEGIN_SRC emacs-lisp :tangle org-ref.el
+(defcustom org-ref-colorize-links
+  t
+  "When non-nil, change colors of links"
+  :group 'org-ref)
+
+
+(defcustom org-ref-cite-color
+  "forest green"
+  "Color of cite like links"
+  :group 'org-ref)
+
+
+(defcustom org-ref-ref-color
+  "dark red"
+  "Color of ref like links"
+  :group 'org-ref)
+
+
+(defcustom org-ref-label-color
+  "dark magenta"
+  "Color of label links"
+  :group 'org-ref)
+
+
+(defvar org-ref-cite-re nil
+ "regexp for cite links")
+
+
+(setq org-ref-cite-re
+      (concat "\\(" (mapconcat
+                    (lambda (x)
+                      (replace-regexp-in-string "\*" "\\\\*" x)
+                      )
+                    org-ref-cite-types "\\|") "\\)"
+  ":\\([a-zA-Z0-9-_:]*,?\\)*"))
+
+
+(setq org-ref-label-re
+      "label:\\([a-zA-Z0-9-_:]*,?\\)*")
+
+
+(setq org-ref-ref-re
+      "ref:\\([a-zA-Z0-9-_:]*,?\\)*")
+
+
+(defface org-ref-cite-face
+  `((t (:inherit org-link :foreground ,org-ref-cite-color)))
+  "Color for cite-like links in org-ref.")
+
+
+(defface org-ref-label-face
+  `((t (:inherit org-link :foreground ,org-ref-label-color)))
+  "Color for ref links in org-ref.")
+
+
+(defface org-ref-ref-face
+  `((t (:inherit org-link :foreground ,org-ref-ref-color)))
+  "Face for ref links in org-ref.")
+
+
+(defun org-ref-colorize-links ()
+  "Colorize org-ref links."
+  (hi-lock-mode 1)
+  (highlight-regexp org-ref-cite-re 'org-ref-cite-face)
+  (highlight-regexp org-ref-label-re 'org-ref-label-face)
+  (highlight-regexp org-ref-ref-re 'org-ref-ref-face))
+
+
+(when org-ref-colorize-links
+  (add-hook 'org-mode-hook 'org-ref-colorize-links))
+#+END_SRC
+
+#+RESULTS:
+
+
 * Links
 Most of this library is the creation of functional links to help with references and citations.
 ** General utilities
 * Links
 Most of this library is the creation of functional links to help with references and citations.
 ** General utilities
@@ -1452,7 +1632,6 @@ The first thing we need is to get the bibtex key we clicked on.
 point to get a comma, or the end of the link, and then backwards
 to get a comma, or the beginning of the link. that delimits the
 keyword we clicked on. We also strip the text properties."
 point to get a comma, or the end of the link, and then backwards
 to get a comma, or the beginning of the link. that delimits the
 keyword we clicked on. We also strip the text properties."
-  (interactive)
   (let* ((object (org-element-context))
         (link-string (org-element-property :path object)))
     ;; you may click on the part before the citations. here we make
   (let* ((object (org-element-context))
         (link-string (org-element-property :path object)))
     ;; you may click on the part before the citations. here we make
@@ -1506,7 +1685,6 @@ internal bibliographies
 
 falling back to what the user has set in org-ref-default-bibliography
 "
 
 falling back to what the user has set in org-ref-default-bibliography
 "
-  (interactive)
   (catch 'result
     (save-excursion
       (goto-char (point-min))
   (catch 'result
     (save-excursion
       (goto-char (point-min))
@@ -1549,9 +1727,15 @@ Now, we can see if an entry is in a file.
 #+BEGIN_SRC emacs-lisp :tangle org-ref.el
 (defun org-ref-key-in-file-p (key filename)
   "determine if the key is in the file"
 #+BEGIN_SRC emacs-lisp :tangle org-ref.el
 (defun org-ref-key-in-file-p (key filename)
   "determine if the key is in the file"
-  (interactive "skey: \nsFile: ")
   (save-current-buffer
     (let ((bibtex-files (list filename)))
   (save-current-buffer
     (let ((bibtex-files (list filename)))
+      ;; This is something I am trying because when the bibtex file is open, and
+      ;; you have added to it, the only way I find to get the update to update
+      ;; is to close it and reopen it. or to save it and revert it.
+      (when (get-file-buffer filename)
+       (set-buffer (get-file-buffer filename))
+       (save-buffer)
+       (revert-buffer t t))
       (bibtex-search-entry key t))))
 #+END_SRC
 
       (bibtex-search-entry key t))))
 #+END_SRC
 
@@ -1560,7 +1744,6 @@ Finally, we want to know which file the key is in.
 #+BEGIN_SRC emacs-lisp :tangle org-ref.el
 (defun org-ref-get-bibtex-key-and-file (&optional key)
   "returns the bibtex key and file that it is in. If no key is provided, get one under point"
 #+BEGIN_SRC emacs-lisp :tangle org-ref.el
 (defun org-ref-get-bibtex-key-and-file (&optional key)
   "returns the bibtex key and file that it is in. If no key is provided, get one under point"
- (interactive)
  (let ((org-ref-bibliography-files (org-ref-find-bibliography))
        (file))
    (unless key
  (let ((org-ref-bibliography-files (org-ref-find-bibliography))
        (file))
    (unless key
@@ -1605,14 +1788,14 @@ We need some convenience functions to open act on the citation at point. These w
         (catch 'done
           (let ((url (bibtex-autokey-get-field "url")))
             (when  url
         (catch 'done
           (let ((url (bibtex-autokey-get-field "url")))
             (when  url
-              (browse-url url)
+              (browse-url (s-trim url))
               (throw 'done nil)))
 
           (let ((doi (bibtex-autokey-get-field "doi")))
             (when doi
               (if (string-match "^http" doi)
                   (browse-url doi)
               (throw 'done nil)))
 
           (let ((doi (bibtex-autokey-get-field "doi")))
             (when doi
               (if (string-match "^http" doi)
                   (browse-url doi)
-                (browse-url (format "http://dx.doi.org/%s" doi)))
+                (browse-url (format "http://dx.doi.org/%s" (s-trim doi))))
               (throw 'done nil))))))))
 
 
               (throw 'done nil))))))))
 
 
@@ -1706,7 +1889,6 @@ Prompt for NEW-FILE includes bib files in org-ref-default-bibliography, and bib
 
 (defun org-ref-get-doi-at-point ()
   "Get doi for key at point."
 
 (defun org-ref-get-doi-at-point ()
   "Get doi for key at point."
-  (interactive)
   (let* ((results (org-ref-get-bibtex-key-and-file))
         (key (car results))
         (bibfile (cdr results))
   (let* ((results (org-ref-get-bibtex-key-and-file))
         (key (car results))
         (bibfile (cdr results))
@@ -1944,7 +2126,25 @@ We will want to generate formatting functions for each citation type. The reason
         ;; bibtex format
        (concat "\\" ,type (when desc (org-ref-format-citation-description desc)) "{"
               (mapconcat (lambda (key) key) (org-ref-split-and-strip-string keyword) ",")
         ;; bibtex format
        (concat "\\" ,type (when desc (org-ref-format-citation-description desc)) "{"
               (mapconcat (lambda (key) key) (org-ref-split-and-strip-string keyword) ",")
-              "}"))))))
+              "}")))
+      ;; for markdown we generate pandoc citations
+      ((eq format 'md)
+       (cond
+       (desc  ;; pre and or post text
+        (let* ((text (split-string desc "::"))
+               (pre (car text))
+               (post (cadr text)))
+          (concat
+           (format "[@%s," keyword)
+           (when pre (format " %s" pre))
+           (when post (format ", %s" post))
+           "]")))
+       (t
+        (format "[%s]"
+                (mapconcat
+                 (lambda (key) (concat "@" key))
+                 (org-ref-split-and-strip-string keyword)
+                 "; "))))))))
 #+END_SRC
 
 
 #+END_SRC
 
 
@@ -1953,15 +2153,18 @@ We create the links by mapping the function onto the list of defined link types.
 
 #+BEGIN_SRC emacs-lisp :tangle org-ref.el
 (defun org-ref-format-citation-description (desc)
 
 #+BEGIN_SRC emacs-lisp :tangle org-ref.el
 (defun org-ref-format-citation-description (desc)
-  "return formatted citation description. if the cite link has a description, it is optional text for the citation command. You can specify pre and post text by separating these with ::."
-  (interactive)
+  "Return formatted citation description.  If the cite link has a
+description, it is optional text for the citation command. You
+can specify pre and post text by separating these with ::, for
+example [[cite:key][pre text::post text]]."
   (cond
    ((string-match "::" desc)
     (format "[%s][%s]" (car (setq results (split-string desc "::"))) (cadr results)))
    (t (format "[%s]" desc))))
 
 (defun org-ref-define-citation-link (type &optional key)
   (cond
    ((string-match "::" desc)
     (format "[%s][%s]" (car (setq results (split-string desc "::"))) (cadr results)))
    (t (format "[%s]" desc))))
 
 (defun org-ref-define-citation-link (type &optional key)
-  "add a citation link for org-ref. With optional key, set the reftex binding. For example:
+  "Add a citation link of TYPE for org-ref.
+With optional KEY, set the reftex binding. For example:
 (org-ref-define-citation-link \"citez\" ?z) will create a new citez link, with reftex key of z,
 and the completion function."
   (interactive "sCitation Type: \ncKey: ")
 (org-ref-define-citation-link \"citez\" ?z) will create a new citez link, with reftex key of z,
 and the completion function."
   (interactive "sCitation Type: \ncKey: ")
@@ -1992,6 +2195,8 @@ and the completion function."
 (mapcar 'org-ref-define-citation-link org-ref-cite-types)
 #+END_SRC
 
 (mapcar 'org-ref-define-citation-link org-ref-cite-types)
 #+END_SRC
 
+#+RESULTS:
+
 *** org-ref-insert-cite-link
 We need a convenient method to insert links. In reftex you use the keystroke C-c ], which gives you a minibuffer to search the bibtex files from. This function is bound to that same keystroke here [[*org-mode%20/%20reftex%20setup][org-mode / reftex setup]]. This function will append to a cite link if you call it while on a link.
 
 *** org-ref-insert-cite-link
 We need a convenient method to insert links. In reftex you use the keystroke C-c ], which gives you a minibuffer to search the bibtex files from. This function is bound to that same keystroke here [[*org-mode%20/%20reftex%20setup][org-mode / reftex setup]]. This function will append to a cite link if you call it while on a link.
 
@@ -2035,8 +2240,7 @@ inserted. Use a prefix arg to get a menu of citation types."
                   (mapconcat 'identity (reftex-citation t) ",")))))
 
       ;; you pressed a C-u so we run this code
                   (mapconcat 'identity (reftex-citation t) ",")))))
 
       ;; you pressed a C-u so we run this code
-      (reftex-citation)))
-  )
+      (reftex-citation))))
 #+END_SRC
 cite:zhou-2004-first-lda-u,paier-2006-errat,boes-2015-estim-bulk
 
 #+END_SRC
 cite:zhou-2004-first-lda-u,paier-2006-errat,boes-2015-estim-bulk
 
@@ -2453,8 +2657,8 @@ Here is the python script for uploading.
 *************** TODO document how to get the cookies
 *************** END
 
 *************** TODO document how to get the cookies
 *************** END
 
-
-#+BEGIN_SRC python :tangle upload_bibtex_citeulike.py
+# :tangle upload_bibtex_citeulike.py
+#+BEGIN_SRC python
 #!python
 import pickle, requests, sys
 
 #!python
 import pickle, requests, sys
 
@@ -2617,7 +2821,6 @@ Makes a new buffer with clickable links."
          (when (-contains? org-ref-cite-types (plist-get plist :type))
            (dolist (key (org-ref-split-and-strip-string (plist-get plist :path)))
              (when (not (index key bibtex-keys))
          (when (-contains? org-ref-cite-types (plist-get plist :type))
            (dolist (key (org-ref-split-and-strip-string (plist-get plist :path)))
              (when (not (index key bibtex-keys))
-               (message-box "%s" link)
                (setq
                 bad-citations
                 (append
                (setq
                 bad-citations
                 (append
@@ -2746,6 +2949,7 @@ Here we develop a similar idea, but instead of an org-buffer with links, we crea
 Now, we have a functions for candidates, we can make helm sources for each one, and then run a helm command to view them.
 
 #+BEGIN_SRC emacs-lisp :tangle org-ref.el
 Now, we have a functions for candidates, we can make helm sources for each one, and then run a helm command to view them.
 
 #+BEGIN_SRC emacs-lisp :tangle org-ref.el
+;;;###autoload
 (defun org-ref ()
   "Opens a helm interface to actions for org-ref.
 Shows bad citations, ref links and labels"
 (defun org-ref ()
   "Opens a helm interface to actions for org-ref.
 Shows bad citations, ref links and labels"
@@ -2966,7 +3170,6 @@ I prefer citations in chronological order within a grouping. These functions sor
 #+BEGIN_SRC emacs-lisp :tangle org-ref.el
 (defun org-ref-get-citation-year (key)
   "get the year of an entry with key. Returns year as a string."
 #+BEGIN_SRC emacs-lisp :tangle org-ref.el
 (defun org-ref-get-citation-year (key)
   "get the year of an entry with key. Returns year as a string."
-  (interactive)
   (let* ((results (org-ref-get-bibtex-key-and-file key))
         (bibfile (cdr results)))
     (with-temp-buffer
   (let* ((results (org-ref-get-bibtex-key-and-file key))
         (bibfile (cdr results)))
     (with-temp-buffer
@@ -2976,7 +3179,7 @@ I prefer citations in chronological order within a grouping. These functions sor
         ))))
 
 (defun org-ref-sort-citation-link ()
         ))))
 
 (defun org-ref-sort-citation-link ()
- "replace link at point with sorted link by year"
+ "Replace link at point with sorted link by year."
  (interactive)
  (let* ((object (org-element-context))
         (type (org-element-property :type object))
  (interactive)
  (let* ((object (org-element-context))
         (type (org-element-property :type object))
@@ -2998,12 +3201,13 @@ I prefer citations in chronological order within a grouping. These functions sor
 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)
 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"
+ "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)
 
  (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)
 (defun org-ref-swap-citation-link (direction)
  "move citation at point in direction +1 is to the right, -1 to the left"
  (interactive)
@@ -3023,7 +3227,17 @@ Sometimes it may be helpful to manually change the order of citations. These fun
          (org-ref-swap-keys i (- i 1) keys))
        (setq keys (mapconcat 'identity keys ","))
        ;; and replace the link with the sorted 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 " "))
+       (cl--set-buffer-substring
+        begin end
+        (concat
+         type ":" keys
+         ;; It seems the space at the end can get consumed, so we see if there
+         ;; is a space, and add it if so. Sometimes there is a comma or period,
+         ;; then we do not want a space.
+         (when
+             (save-excursion
+               (goto-char end)
+               (looking-back " ")) " ")))
        ;; now go forward to key so we can move with the key
        (re-search-forward key)
        (goto-char (match-beginning 0)))))
        ;; now go forward to key so we can move with the key
        (re-search-forward key)
        (goto-char (match-beginning 0)))))
@@ -3198,8 +3412,138 @@ I like convenience. Here are some aliases for faster typing.
 * 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.
 
 * 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.
 
+Let us add keywords as a searchable field.
+#+BEGIN_SRC emacs-lisp  :tangle org-ref.el
+(setq helm-bibtex-additional-search-fields '(keywords))
+#+END_SRC
+
+Next, we are going to add keywords to the helm interface. This modifies the helm-bibtex function to add our keywords.
+#+BEGIN_SRC emacs-lisp :tangle org-ref.el
+(defun helm-bibtex-candidates-formatter (candidates source)
+  "Formats BibTeX entries for display in results list."
+  (cl-loop
+    with width = (with-helm-window (window-width))
+    for entry in candidates
+    for entry = (cdr entry)
+    for entry-key = (helm-bibtex-get-value entry 'entry-key)
+    for fields = (--map (helm-bibtex-clean-string
+                          (helm-bibtex-get-value entry it " "))
+                        '(author title year has-pdf has-note entry-type))
+    for fields = (-update-at 0 'helm-bibtex-shorten-authors fields)
+    for fields = (append fields
+                        (list  (or (helm-bibtex-get-value entry 'keywords)
+                                   "" )))
+    collect
+    (cons (s-format "$0 $1 $2 $3 $4$5 $6" 'elt
+            (-zip-with (lambda (f w) (truncate-string-to-width f w 0 ?\s))
+                       fields (list 36 (- width 85) 4 1 1 7 7)))
+          entry-key)))
+#+END_SRC
+
+Next, we add some functions to add keywords to a bibtex entry using a helm interface, and a new action to add keywords to entries from helm-bibtex.
+#+BEGIN_SRC emacs-lisp  :tangle org-ref.el
+;; adapted from bibtex-utils.el
+;; these are candidates for selecting keywords/tags
+(defun org-ref-bibtex-keywords ()
+  "Get keywords defined in current bibtex file.
+These are in the keywords field, and are comma or semicolon separated."
+  (save-excursion
+    (goto-char (point-min))
+    (let (keywords kstring)
+      (while (re-search-forward "^\\s-*keywords.*{\\([^}]+\\)}" nil t)
+        ;; TWS - remove newlines/multiple spaces:
+       (setq kstring (replace-regexp-in-string "[ \t\n]+" " " (match-string 1)))
+       (mapc
+        (lambda (v)
+          (add-to-list 'keywords v t))
+        (split-string kstring "\\(,\\|;\\)[ \n]*\\|{\\|}" t)))
+      keywords)))
+
+
+(defun org-ref-set-bibtex-keywords (keywords &optional arg)
+  "Add KEYWORDS to a bibtex entry.
+If KEYWORDS is a list, it is converted to a comma-separated string. The KEYWORDS are added to the beginning of the field. Otherwise KEYWORDS should be a string of comma-separate keywords."
+  (interactive "sKeywords: \nP")
+  (bibtex-set-field
+   "keywords"
+   (if arg
+       ;; replace with arg
+       (if (listp keywords)
+          (mapconcat 'identity keywords ", ")
+        keywords)
+     ;; else concatentate
+     (concat
+      (if (listp keywords)
+         (mapconcat 'identity keywords ", ")
+        keywords)
+      (when (not (string= "" (bibtex-autokey-get-field "keywords")))
+       (concat ", "  (bibtex-autokey-get-field "keywords"))))))
+  (save-buffer))
+
+
+(defun helm-tag-bibtex-entry ()
+  "Helm interface to add keywords to a bibtex entry.
+Run this with the point in a bibtex entry."
+  (interactive)
+  (let ((keyword-source `((name . "Existing keywords")
+                         (candidates . ,(org-ref-bibtex-keywords))
+                         (action . (lambda (candidate)
+                                     (org-ref-set-bibtex-keywords
+                                      (mapconcat
+                                       'identity
+                                       (helm-marked-candidates)
+                                       ", "))))))
+       (fallback-source `((name . "Add new keywords")
+                          (dummy)
+                          (action . (lambda (candidate)
+                                      (org-ref-set-bibtex-keywords helm-pattern)
+                                      )))))
+    (helm :sources '(keyword-source fallback-source))))
+
+(defun helm-bibtex-show-entry (key)
+  "Show the entry in the BibTeX file.
+The original function in helm-bibtex has a bug where it finds the
+first key that partially matches. This version avoids that."
+  (catch 'break
+    (dolist (bibtex-file (if (listp helm-bibtex-bibliography)
+                             helm-bibtex-bibliography
+                           (list helm-bibtex-bibliography)))
+      (let ((buf (helm-bibtex-buffer-visiting bibtex-file))
+            (entries '()))
+        (find-file bibtex-file)
+        (bibtex-map-entries
+        (lambda (key start end)
+          (add-to-list 'entries (cons key start))))
+        (if (assoc key entries)
+           (progn
+             (goto-char (cdr (assoc key entries)))
+             (throw 'break t))
+          (unless buf
+            (kill-buffer)))))))
+
+(defun org-ref-helm-tag-entries (candidates)
+  "Set tags on selected bibtex entries from helm-bibtex.
+User is prompted for tags. This function is called from `helm-bibtex'."
+  (message "")
+  (let ((keywords (read-input "Keywords (comma separated): ")))
+    (loop for key in (helm-marked-candidates)
+         do
+         (save-window-excursion
+           (helm-bibtex-show-entry key)
+           (bibtex-set-field
+            "keywords"
+            (concat
+             keywords
+             ", " (bibtex-autokey-get-field "keywords")))
+           (save-buffer)))))
+#+END_SRC
+
+Next, adapt the helm-bibtex source with these features:
+
 1. Make the default action to insert selected keys.
 2. Make open entry second action
 1. Make the default action to insert selected keys.
 2. Make open entry second action
+3. Add some features for adding keywords to bibtex entries.
+
 #+BEGIN_SRC emacs-lisp :tangle org-ref.el
 (setq helm-source-bibtex
       '((name                                      . "BibTeX entries")
 #+BEGIN_SRC emacs-lisp :tangle org-ref.el
 (setq helm-source-bibtex
       '((name                                      . "BibTeX entries")
@@ -3210,11 +3554,12 @@ I like convenience. Here are some aliases for faster typing.
                   ("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)
                   ("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 formatted 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)
                   ("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)
+                   ("Add keywords to entries"      . org-ref-helm-tag-entries)
                   ))))
 #+END_SRC
 
                   ))))
 #+END_SRC
 
@@ -3293,6 +3638,7 @@ C-u C-u will change the key at point to the selected keys.
 (setq helm-bibtex-format-citation-functions
       '((org-mode . helm-bibtex-format-org-ref)))
 
 (setq helm-bibtex-format-citation-functions
       '((org-mode . helm-bibtex-format-org-ref)))
 
+;;;###autoload
 (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.
 (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.
@@ -3307,7 +3653,6 @@ With two prefix args, insert a label link."
    ((equal arg '(16))
     (org-ref-helm-insert-label-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
 
 ;; add our own fallback entries where we want them. These appear in reverse order of adding in the menu
 (setq helm-bibtex-fallback-options
@@ -3328,7 +3673,6 @@ This code provides a helm interface to things you can do when you click on a cit
 #+BEGIN_SRC emacs-lisp :tangle org-ref.el
 (defun org-ref-get-citation-string-at-point ()
   "Get a string of a formatted citation"
 #+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)))
   (let* ((results (org-ref-get-bibtex-key-and-file))
         (key (car results))
         (bibfile (cdr results)))
@@ -3340,10 +3684,10 @@ This code provides a helm interface to things you can do when you click on a cit
            (org-ref-bib-citation)))
       "!!! No entry found !!!" )))
 
            (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."
 (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))
   (let* ((results (org-ref-get-bibtex-key-and-file))
         (key (car results))
          (pdf-file (format (concat org-ref-pdf-directory "%s.pdf") key))
@@ -3448,8 +3792,10 @@ This is a list of cons cells '((\"description\" . action)). The action function
  '("Example" . (lambda () (message-box "You did it!")))
  t)
 
  '("Example" . (lambda () (message-box "You did it!")))
  t)
 
+;;;###autoload
 (defun org-ref-cite-click-helm (key)
 (defun org-ref-cite-click-helm (key)
-  "subtle points.
+  "Open helm for actions on a cite link.
+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)
 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)
@@ -3473,9 +3819,47 @@ This is a list of cons cells '((\"description\" . action)). The action function
 #+RESULTS:
 : org-ref-cite-click-helm
 
 #+RESULTS:
 : org-ref-cite-click-helm
 
+** A hydra click interface
+I like hydra a lot. Here we define a hydra menu you might like for the link click action.
+
+#+BEGIN_SRC emacs-lisp :tangle org-ref.el
+(when (featurep 'hydra)
+  (require 'hydra)
+  (setq hydra-is-helpful t)
+
+  (defhydra org-ref-cite-hydra (:color blue)
+    "
+_p_: Open pdf     _w_: WOS          _g_: Google Scholar _K_: Copy citation to clipboard
+_u_: Open url     _r_: WOS related  _P_: Pubmed         _k_: Copy key to clipboard
+_n_: Open notes   _c_: WOS citing   _C_: Crossref       _f_: Copy bibtex entry to file
+_o_: Open entry   _e_: Email entry and pdf
+"
+    ("o" org-ref-open-citation-at-point nil)
+    ("p" org-ref-open-pdf-at-point nil)
+    ("n" org-ref-open-notes-at-point nil)
+    ("u" org-ref-open-url-at-point nil)
+    ("w" org-ref-wos-at-point nil)
+    ("r" org-ref-wos-related-at-point nil)
+    ("c" org-ref-wos-citing-at-point nil)
+    ("g" org-ref-google-scholar-at-point nil)
+    ("P" org-ref-pubmed-at-point nil)
+    ("C" org-ref-crossref-at-point nil)
+    ("K" org-ref-copy-entry-as-summary nil)
+    ("k" (progn
+          (kill-new
+           (car (org-ref-get-bibtex-key-and-file)))) nil)
+    ("f" org-ref-copy-entry-at-point-to-file nil)
+
+    ("e" (save-excursion
+          (org-ref-open-citation-at-point)
+          (email-bibtex-entry)) nil)))
+#+END_SRC
+
 * End of code
 #+BEGIN_SRC emacs-lisp :tangle org-ref.el
 (provide 'org-ref)
 * End of code
 #+BEGIN_SRC emacs-lisp :tangle org-ref.el
 (provide 'org-ref)
+
+;;; org-ref.el ends here
 #+END_SRC
 
 * Build                                                                   :noexport:
 #+END_SRC
 
 * Build                                                                   :noexport: