-** Finding non-ascii characters
-I like my bibtex files to be 100% ascii. This function finds the non-ascii characters so you can replace them.
-
-#+BEGIN_SRC emacs-lisp :tangle org-ref.el
-(defun org-ref-find-non-ascii-characters ()
- "finds non-ascii characters in the buffer. Useful for cleaning up bibtex files"
- (interactive)
- (occur "[^[:ascii:]]"))
-#+END_SRC
-
-** Resort a bibtex entry
-I like neat and orderly bibtex entries.That means the fields are in a standard order that I like. This function reorders the fields in an entry for articles, and makes sure the fields are in lowercase.
-
-#+BEGIN_SRC emacs-lisp :tangle org-ref.el
-(defun org-ref-sort-bibtex-entry ()
- "sort fields of entry in standard order and downcase them"
- (interactive)
- (bibtex-beginning-of-entry)
- (let* ((master '("author" "title" "journal" "volume" "number" "pages" "year" "doi" "url"))
- (entry (bibtex-parse-entry))
- (entry-fields)
- (other-fields)
- (type (cdr (assoc "=type=" entry)))
- (key (cdr (assoc "=key=" entry))))
-
- ;; these are the fields we want to order that are in this entry
- (setq entry-fields (mapcar (lambda (x) (car x)) entry))
- ;; we do not want to reenter these fields
- (setq entry-fields (remove "=key=" entry-fields))
- (setq entry-fields (remove "=type=" entry-fields))
-
- ;;these are the other fields in the entry
- (setq other-fields (remove-if-not (lambda(x) (not (member x master))) entry-fields))
-
- (cond
- ;; right now we only resort articles
- ((string= (downcase type) "article")
- (bibtex-kill-entry)
- (insert
- (concat "@article{" key ",\n"
- (mapconcat
- (lambda (field)
- (when (member field entry-fields)
- (format "%s = %s," (downcase field) (cdr (assoc field entry))))) master "\n")
- (mapconcat
- (lambda (field)
- (format "%s = %s," (downcase field) (cdr (assoc field entry)))) other-fields "\n")
- "\n}\n\n"))
- (bibtex-find-entry key)
- (bibtex-fill-entry)
- (bibtex-clean-entry)
- ))))
-#+END_SRC
-
-** Clean a bibtex entry
- I like neat and orderly bibtex entries. This code will eventually replace the key with my style key, clean the entry, and sort the fields in the order I like them.
-see [[file:emacs-24.3/lisp/textmodes/bibtex.el::bibtex-autokey-before-presentation-function]] for how to set a function that checks for uniqueness of the key.
-#+BEGIN_SRC emacs-lisp :tangle org-ref.el
-(defun org-ref-clean-bibtex-entry(&optional keep-key)
- "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"
- (interactive "P")
- (bibtex-beginning-of-entry)
-(end-of-line)
- ;; some entries do not have a key or comma in first line. We check and add it, if needed.
- (unless (string-match ",$" (thing-at-point 'line))
- (end-of-line)
- (insert ","))
-
- ;; check for empty pages, and put eid or article id in its place
- (let ((entry (bibtex-parse-entry))
- (pages (bibtex-autokey-get-field "pages"))
- (year (bibtex-autokey-get-field "year"))
- (doi (bibtex-autokey-get-field "doi"))
- ;; The Journal of Chemical Physics uses eid
- (eid (bibtex-autokey-get-field "eid")))
-
- ;; replace http://dx.doi.org/ in doi. some journals put that in,
- ;; but we only want the doi.
- (when (string-match "^http://dx.doi.org/" doi)
- (bibtex-beginning-of-entry)
- (goto-char (car (cdr (bibtex-search-forward-field "doi" t))))
- (bibtex-kill-field)
- (bibtex-make-field "doi")
- (backward-char)
- (insert (replace-regexp-in-string "^http://dx.doi.org/" "" doi)))
-
- ;; asap articles often set year to 0, which messes up key
- ;; generation. fix that.
- (when (string= "0" year)
- (bibtex-beginning-of-entry)
- (goto-char (car (cdr (bibtex-search-forward-field "year" t))))
- (bibtex-kill-field)
- (bibtex-make-field "year")
- (backward-char)
- (insert (read-string "Enter year: ")))
-
- ;; fix pages if they are empty if there is an eid to put there.
- (when (string= "-" pages)
- (when eid
- (bibtex-beginning-of-entry)
- ;; this seems like a clunky way to set the pages field.But I
- ;; cannot find a better way.
- (goto-char (car (cdr (bibtex-search-forward-field "pages" t))))
- (bibtex-kill-field)
- (bibtex-make-field "pages")
- (backward-char)
- (insert eid)))
-
- ;; replace naked & with \&
- (save-restriction
- (bibtex-narrow-to-entry)
- (bibtex-beginning-of-entry)
- (message "checking &")
- (replace-regexp " & " " \\\\& ")
- (widen))
-
- ;; generate a key, and if it duplicates an existing key, edit it.
- (unless keep-key
- (let ((key (bibtex-generate-autokey)))
-
- ;; first we delete the existing key
- (bibtex-beginning-of-entry)
- (re-search-forward bibtex-entry-maybe-empty-head)
- (if (match-beginning bibtex-key-in-head)
- (delete-region (match-beginning bibtex-key-in-head)
- (match-end bibtex-key-in-head)))
- ;; check if the key is in the buffer
- (when (save-excursion
- (bibtex-search-entry key))
- (save-excursion
- (bibtex-search-entry key)
- (bibtex-copy-entry-as-kill)
- (switch-to-buffer-other-window "*duplicate entry*")
- (bibtex-yank))
- (setq key (bibtex-read-key "Duplicate Key found, edit: " key)))
-
- (insert key)
- (kill-new key))) ;; save key for pasting
-
- ;; run hooks. each of these operates on the entry with no arguments.
- ;; this did not work like i thought, it gives a symbolp error.
- ;; (run-hooks org-ref-clean-bibtex-entry-hook)
- (mapcar (lambda (x)
- (save-restriction
- (save-excursion
- (funcall x))))
- org-ref-clean-bibtex-entry-hook)
-
- ;; sort fields within entry
- (org-ref-sort-bibtex-entry)
- ;; check for non-ascii characters
- (occur "[^[:ascii:]]")
- ))
-#+END_SRC
-
-#+RESULTS:
-: org-ref-clean-bibtex-entry
-
-** Sort the entries in a citation link by year
-I prefer citations in chronological order within a grouping. These functions sort the link under the cursor by year.
-
-#+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
- (insert-file-contents bibfile)
- (bibtex-search-entry key nil 0)
- (prog1 (reftex-get-bib-field "year" (bibtex-parse-entry t))
- ))))
-
-(defun org-ref-sort-citation-link ()
- "replace link at point with sorted link by year"
- (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))
- keys years data)
- (setq keys (org-ref-split-and-strip-string link-string))
- (setq years (mapcar 'org-ref-get-citation-year keys))
- (setq data (mapcar* (lambda (a b) `(,a . ,b)) years keys))
- (setq data (cl-sort data (lambda (x y) (< (string-to-int (car x)) (string-to-int (car y))))))
- ;; now get the keys separated by commas
- (setq keys (mapconcat (lambda (x) (cdr x)) data ","))
- ;; and replace the link with the sorted keys
- (cl--set-buffer-substring begin end (concat type ":" keys))))
-#+END_SRC
-
-** 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)