-** Storing links to a bibtex entry
-org-mode already defines a store link function for bibtex entries. It does not store the link I want though, it only stores a brief citation of the entry. I want a citation link. Here is a function to do that.
-
-#+BEGIN_SRC emacs-lisp :tangle org-ref.el
-(defun org-ref-store-bibtex-entry-link ()
- "Save a citation link to the current bibtex entry. Saves in the default link type."
- (interactive)
- (let ((link (concat org-ref-default-citation-link
- ":"
- (save-excursion
- (bibtex-beginning-of-entry)
- (reftex-get-bib-field "=key=" (bibtex-parse-entry))))))
- (message "saved %s" link)
- (push (list link) org-stored-links)
- (car org-stored-links)))
-#+END_SRC
-
-** Index entries
-org-ref minimally supports index entries. To make an index in a file, you should put in the LaTeX header these lines
-
-
-#+LATEX_HEADER: \usepackage{makeidx}
-#+LATEX_HEADER: \makeindex
-
-
-Finally, put \makeindex at the end of the document where you want the index to appear. You will need to run the makeindex program at an appropriate point in your LaTeX to pdf, or use ox-manuscript, which will do it for you.
-
-
-Use index links to create entries (see http://en.wikibooks.org/wiki/LaTeX/Indexing). Clicking on an index link runs occur on the buffer for the entry. The link exports to LaTeX. Some links may need to be enclosed in double brackets if they have spaces in them.
-
-
-index:hello
-index:hello!Peter
-[[index:hello!Sam@\textsl{Sam}]]
-[[index:Lin@\textbf{Lin}]]
-[[index:Joe|textit]]
-[[index:Lin@\textbf{Lin}]]
-[[index:Peter|see {hello}]]
-[[index:Jen|seealso{Jenny}]]
-
-index:encodings!input!cp850
-
-#+BEGIN_SRC emacs-lisp :tangle org-ref.el
-(org-add-link-type
- "index"
- (lambda (path)
- (occur path))
-
- (lambda (path desc format)
- (cond
- ((eq format 'latex)
- (format "\\index{%s}" path)))))
-
-;; this will generate a temporary index of entries in the file.
-(org-add-link-type
- "printindex"
- (lambda (path)
- (let ((*index-links* '())
- (*initial-letters* '()))
-
- ;; get links
- (org-element-map (org-element-parse-buffer) 'link
- (lambda (link)
- (let ((type (nth 0 link))
- (plist (nth 1 link)))
-
- (when (equal (plist-get plist ':type) "index")
- (add-to-list
- '*index-links*
- (cons (plist-get plist :path)
- (format
- "[[elisp:(progn (switch-to-buffer \"%s\") (goto-char %s))][%s]]"
-(current-buffer)
- (plist-get plist :begin) ;; position of link
- ;; grab a description
- (save-excursion
- (goto-char (plist-get plist :begin))
- (if (thing-at-point 'sentence)
- ;; get a sentence
- (replace-regexp-in-string
- "\n" "" (thing-at-point 'sentence))
- ;; or call it a link
- "link")))))))))
-
- ;; sort the links
- (setq *index-links* (cl-sort *index-links* 'string-lessp :key 'car))
-
- ;; now first letters
- (dolist (link *index-links*)
- (add-to-list '*initial-letters* (substring (car link) 0 1) t))
-
- ;; now create the index
- (switch-to-buffer (get-buffer-create "*index*"))
- (org-mode)
- (erase-buffer)
- (insert "#+TITLE: Index\n\n")
- (dolist (letter *initial-letters*)
- (insert (format "* %s\n" (upcase letter)))
- ;; now process the links
- (while (and
- ,*index-links*
- (string= letter (substring (car (car *index-links*)) 0 1)))
- (let ((link (pop *index-links*)))
- (insert (format "%s %s\n\n" (car link) (cdr link))))))
- (switch-to-buffer "*index*")))
- ;; formatting
- (lambda (path desc format)
- (cond
- ((eq format 'latex)
- (format "\\printindex")))))
-#+END_SRC
-
-#+RESULTS:
-| lambda | (path) | (let ((*index-links* (quote nil)) (*initial-letters* (quote nil))) (org-element-map (org-element-parse-buffer) (quote link) (lambda (link) (let ((type (nth 0 link)) (plist (nth 1 link))) (when (equal (plist-get plist (quote :type)) index) (add-to-list (quote *index-links*) (cons (plist-get plist :path) (format [[elisp:(progn (switch-to-buffer "%s") (goto-char %s))][%s]] (current-buffer) (plist-get plist :begin) (save-excursion (goto-char (plist-get plist :begin)) (if (thing-at-point (quote sentence)) (replace-regexp-in-string \n (thing-at-point (quote sentence))) link))))))))) (setq *index-links* (cl-sort *index-links* (quote string-lessp) :key (quote car))) (dolist (link *index-links*) (add-to-list (quote *initial-letters*) (substring (car link) 0 1) t)) (switch-to-buffer (get-buffer-create *index*)) (org-mode) (erase-buffer) (insert #+TITLE: Index\n\n) (dolist (letter *initial-letters*) (insert (format * %s\n (upcase letter))) (while (and *index-links* (string= letter (substring (car (car *index-links*)) 0 1))) (let ((link (pop *index-links*))) (insert (format %s %s\n\n (car link) (cdr link)))))) (switch-to-buffer *index*)) |
-| lambda | (path desc format) | (cond ((eq format (quote latex)) (format \printindex))) |
-
-** Glossary
-org-ref provides some minimal support for a glossary. See http://en.wikibooks.org/wiki/LaTeX/Glossary for details. You need to put these lines in the header.
-
-#+LATEX_HEADER: \usepackage{glossaries}
-#+LATEX_HEADER: \makeglossaries
-
-And at the end of the document put \makeglossaries.
-
-#+BEGIN_SRC emacs-lisp :tangle org-ref.el
-(org-add-link-type
- "newglossaryentry"
- nil ;; no follow action
- (lambda (path desc format)
- (cond
- ((eq format 'latex)
- (format "\\newglossaryentry{%s}{%s}" path desc)))))
-
-
-;; link to entry
-(org-add-link-type
- "gls"
- nil ;; no follow action
- (lambda (path desc format)
- (cond
- ((eq format 'latex)
- (format "\\gls{%s}" path)))))
-
-;; plural
-(org-add-link-type
- "glspl"
- nil ;; no follow action
- (lambda (path desc format)
- (cond
- ((eq format 'latex)
- (format "\\glspl{%s}" path)))))
-
-;; capitalized link
-(org-add-link-type
- "Gls"
- nil ;; no follow action
- (lambda (path desc format)
- (cond
- ((eq format 'latex)
- (format "\\Gls{%s}" path)))))
-
-;; capitalized link
-(org-add-link-type
- "Glspl"
- nil ;; no follow action
- (lambda (path desc format)
- (cond
- ((eq format 'latex)
- (format "\\Glspl{%s}" path)))))
-#+END_SRC
-
-
-
-* Utilities
-** create simple text citation from bibtex entry
-
-#+BEGIN_SRC emacs-lisp :tangle org-ref.el
-(defun org-ref-bib-citation ()
- "From a bibtex entry, create and return a simple citation string.
-This assumes you are in an article."
-
- (bibtex-beginning-of-entry)
- (let* ((cb (current-buffer))
- (bibtex-expand-strings t)
- (entry (loop for (key . value) in (bibtex-parse-entry t)
- collect (cons (downcase key) value)))
- (title (replace-regexp-in-string "\n\\|\t\\|\s+" " " (reftex-get-bib-field "title" entry)))
- (year (reftex-get-bib-field "year" entry))
- (author (replace-regexp-in-string "\n\\|\t\\|\s+" " " (reftex-get-bib-field "author" entry)))
- (key (reftex-get-bib-field "=key=" entry))
- (journal (reftex-get-bib-field "journal" entry))
- (volume (reftex-get-bib-field "volume" entry))
- (pages (reftex-get-bib-field "pages" entry))
- (doi (reftex-get-bib-field "doi" entry))
- (url (reftex-get-bib-field "url" entry))
- )
- ;;authors, "title", Journal, vol(iss):pages (year).
- (format "%s, \"%s\", %s, %s:%s (%s)"
- author title journal volume pages year)))
-#+END_SRC
-
-#+RESULTS:
-: org-ref-bib-citation
-
-
-#+BEGIN_SRC emacs-lisp :tangle org-ref.el
-(defun org-ref-bib-html-citation ()
- "from a bibtex entry, create and return a simple citation with html links."
-
- (bibtex-beginning-of-entry)
- (let* ((cb (current-buffer))
- (bibtex-expand-strings t)
- (entry (loop for (key . value) in (bibtex-parse-entry t)
- collect (cons (downcase key) value)))
- (title (replace-regexp-in-string "\n\\|\t\\|\s+" " " (reftex-get-bib-field "title" entry)))
- (year (reftex-get-bib-field "year" entry))
- (author (replace-regexp-in-string "\n\\|\t\\|\s+" " " (reftex-get-bib-field "author" entry)))
- (key (reftex-get-bib-field "=key=" entry))
- (journal (reftex-get-bib-field "journal" entry))
- (volume (reftex-get-bib-field "volume" entry))
- (pages (reftex-get-bib-field "pages" entry))
- (doi (reftex-get-bib-field "doi" entry))
- (url (reftex-get-bib-field "url" entry))
- )
- ;;authors, "title", Journal, vol(iss):pages (year).
- (concat (format "%s, \"%s\", %s, %s:%s (%s)."
- author title journal volume pages year)
- (when url (format " <a href=\"%s\">link</a>" url))
- (when doi (format " <a href=\"http://dx.doi.org/%s\">doi</a>" doi)))
- ))
-#+END_SRC
-
-** open pdf from bibtex
-We bind this to a key here: [[*key%20bindings%20for%20utilities][key bindings for utilities]].
-#+BEGIN_SRC emacs-lisp :tangle org-ref.el
-(defun org-ref-open-bibtex-pdf ()
- "open pdf for a bibtex entry, if it exists. assumes point is in
-the entry of interest in the bibfile. but does not check that."
- (interactive)
- (save-excursion
- (bibtex-beginning-of-entry)
- (let* ((bibtex-expand-strings t)
- (entry (bibtex-parse-entry t))
- (key (reftex-get-bib-field "=key=" entry))
- (pdf (format (concat org-ref-pdf-directory "%s.pdf") key)))
- (message "%s" pdf)
- (if (file-exists-p pdf)
- (org-open-link-from-string (format "[[file:%s]]" pdf))
- (ding)))))
-#+END_SRC
-
-** open notes from bibtex
-We bind this to a key here [[*key%20bindings%20for%20utilities][key bindings for utilities]].
-
-#+BEGIN_SRC emacs-lisp :tangle org-ref.el
-(defun org-ref-open-bibtex-notes ()
- "from a bibtex entry, open the notes if they exist, and create a heading if they do not.
-
-I never did figure out how to use reftex to make this happen
-non-interactively. the reftex-format-citation function did not
-work perfectly; there were carriage returns in the strings, and
-it did not put the key where it needed to be. so, below I replace
-the carriage returns and extra spaces with a single space and
-construct the heading by hand."
- (interactive)
-
- (bibtex-beginning-of-entry)
- (let* ((cb (current-buffer))
- (bibtex-expand-strings t)
- (entry (loop for (key . value) in (bibtex-parse-entry t)
- collect (cons (downcase key) value)))
- (title (replace-regexp-in-string "\n\\|\t\\|\s+" " " (reftex-get-bib-field "title" entry)))
- (year (reftex-get-bib-field "year" entry))
- (author (replace-regexp-in-string "\n\\|\t\\|\s+" " " (reftex-get-bib-field "author" entry)))
- (key (reftex-get-bib-field "=key=" entry))
- (journal (reftex-get-bib-field "journal" entry))
- (volume (reftex-get-bib-field "volume" entry))
- (pages (reftex-get-bib-field "pages" entry))
- (doi (reftex-get-bib-field "doi" entry))
- (url (reftex-get-bib-field "url" entry))
- )
-
- ;; save key to clipboard to make saving pdf later easier by pasting.
- (with-temp-buffer
- (insert key)
- (kill-ring-save (point-min) (point-max)))
-
- ;; now look for entry in the notes file
- (if org-ref-bibliography-notes
- (find-file-other-window org-ref-bibliography-notes)
- (error "org-ref-bib-bibliography-notes is not set to anything"))
-
- (goto-char (point-min))
- ;; put new entry in notes if we don't find it.
- (if (re-search-forward (format ":Custom_ID: %s$" key) nil 'end)
- (funcall org-ref-open-notes-function)
- ;; no entry found, so add one
- (insert (format "\n** TODO %s - %s" year title))
- (insert (format"
- :PROPERTIES:
- :Custom_ID: %s
- :AUTHOR: %s
- :JOURNAL: %s
- :YEAR: %s
- :VOLUME: %s
- :PAGES: %s
- :DOI: %s
- :URL: %s
- :END:
-[[cite:%s]] [[file:%s/%s.pdf][pdf]]\n\n"
-key author journal year volume pages doi url key org-ref-pdf-directory key))
-(save-buffer))))
-#+END_SRC
-
-#+BEGIN_SRC emacs-lisp :tangle org-ref.el
-(defun org-ref-open-notes-from-reftex ()
- "Call reftex, and open notes for selected entry."
- (interactive)
- (let ((bibtex-key )))
-
- ;; now look for entry in the notes file
- (if org-ref-bibliography-notes
- (find-file-other-window org-ref-bibliography-notes)
- (error "org-ref-bib-bibliography-notes is not set to anything"))
-
- (goto-char (point-min))
-
- (re-search-forward (format
- ":Custom_ID: %s$"
- (first (reftex-citation t)) nil 'end))
- (funcall org-ref-open-notes-function))
-#+END_SRC
-
-** open url in browser from bibtex
-
-We bind this to a key here [[*key%20bindings%20for%20utilities][key bindings for utilities]].
-
-+ This function may be duplicative of bibtex-url. But I think my function is better unless you do some complicated customization of bibtex-generate-url-list.
-
-#+BEGIN_SRC emacs-lisp :tangle org-ref.el
-(defun org-ref-open-in-browser ()
- "Open the bibtex entry at point in a browser using the url field or doi field"
-(interactive)
-(save-excursion
- (bibtex-beginning-of-entry)
- (catch 'done
- (let ((url (bibtex-autokey-get-field "url")))
- (when url
- (browse-url url)
- (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)))
- (throw 'done nil)))
- (message "No url or doi found"))))
-#+END_SRC
-
-** citeulike
- I discovered you could upload a bibtex entry to citeulike using http requests. The upload is actually done by a [[*The%20upload%20script][python script]], because it was easy to write. Here is the emacs command to do this. It is not a fast operation, and do not use it frequently.
-
-*** function to upload bibtex to citeulike
-
-#+BEGIN_SRC emacs-lisp :tangle org-ref.el
-(defun org-ref-upload-bibtex-entry-to-citeulike ()
- "with point in a bibtex entry get bibtex string and submit to citeulike.
-
-Relies on the python script /upload_bibtex_citeulike.py being in the user directory."
- (interactive)
- (message "uploading to citeulike")
- (save-restriction
- (bibtex-narrow-to-entry)
- (let ((startpos (point-min))
- (endpos (point-max))
- (bibtex-string (buffer-string))
- (script (concat "python " starter-kit-dir "/upload_bibtex_citeulike.py&")))
- (with-temp-buffer (insert bibtex-string)
- (shell-command-on-region (point-min) (point-max) script t nil nil t)))))
-#+END_SRC
-
-*** The upload script
-Here is the python script for uploading.
-
-*************** TODO document how to get the cookies
-*************** END
-
-
-#+BEGIN_SRC python :tangle upload_bibtex_citeulike.py
-#!python
-import pickle, requests, sys
-
-# reload cookies
-with open('c:/Users/jkitchin/Dropbox/blogofile-jkitchin.github.com/_blog/cookies.pckl', 'rb') as f:
- cookies = pickle.load(f)
-
-url = 'http://www.citeulike.org/profile/jkitchin/import_do'
-
-bibtex = sys.stdin.read()
-
-data = {'pasted':bibtex,
- 'to_read':2,
- 'tag_parsing':'simple',
- 'strip_brackets':'no',
- 'update_id':'bib-key',
- 'btn_bibtex':'Import BibTeX file ...'}
-
-headers = {'content-type': 'multipart/form-data',
- 'User-Agent':'jkitchin/johnrkitchin@gmail.com bibtexupload'}
-
-r = requests.post(url, headers=headers, data=data, cookies=cookies, files={})
-print r
-#+END_SRC
-
-** Build a pdf from a bibtex file
- It is useful to have a pdf version of an entire bibliography to check it for formatting, spelling, or to share it. This function creates a pdf from a bibtex file. I only include the packages I commonly use in my bitex files.
-
-#+BEGIN_SRC emacs-lisp :tangle org-ref.el
-(defun org-ref-build-full-bibliography ()
- "build pdf of all bibtex entries, and open it."
- (interactive)
- (let* ((bibfile (file-name-nondirectory (buffer-file-name)))
- (bib-base (file-name-sans-extension bibfile))
- (texfile (concat bib-base ".tex"))
- (pdffile (concat bib-base ".pdf")))
- (find-file texfile)
- (erase-buffer)
- (insert (format "\\documentclass[12pt]{article}
-\\usepackage[version=3]{mhchem}
-\\usepackage{url}
-\\usepackage[numbers]{natbib}
-\\usepackage[colorlinks=true, linkcolor=blue, urlcolor=blue, pdfstartview=FitH]{hyperref}
-\\usepackage{doi}
-\\begin{document}
-\\nocite{*}
-\\bibliographystyle{unsrtnat}
-\\bibliography{%s}
-\\end{document}" bib-base))
- (save-buffer)
- (shell-command (concat "pdflatex " bib-base))
- (shell-command (concat "bibtex " bib-base))
- (shell-command (concat "pdflatex " bib-base))
- (shell-command (concat "pdflatex " bib-base))
- (kill-buffer texfile)
- (org-open-file pdffile)
- ))
-#+END_SRC
-
-** Extract bibtex entries cited in an org-file
-When you use your default bibliography file, and you want to send an org-file to a collaborator, you may need to include bibtex entries so the other person can see them. This function does that and puts the entries in a section at the end of the document that can be tangled to a bib-file.
-
-#+BEGIN_SRC emacs-lisp :tangle org-ref.el
-(defun org-ref-extract-bibtex-entries ()
- "extract the bibtex entries referred to by cite links in the current buffer into a src block at the bottom of the current buffer.
-
-If no bibliography is in the buffer the `reftex-default-bibliography' is used."
- (interactive)
- (let* ((temporary-file-directory (file-name-directory (buffer-file-name)))
- (tempname (make-temp-file "extract-bib"))
- (contents (buffer-string))
- (cb (current-buffer))
- basename texfile bibfile results)
-
- ;; open tempfile and insert org-buffer contents
- (find-file tempname)
- (insert contents)
- (setq basename (file-name-sans-extension
- (file-name-nondirectory buffer-file-name))
- texfile (concat tempname ".tex")
- bibfile (concat tempname ".bib"))
-
- ;; see if we have a bibliography, and insert the default one if not.
- (save-excursion
- (goto-char (point-min))
- (unless (re-search-forward "^bibliography:" (point-max) 'end)
- (insert (format "\nbibliography:%s"
- (mapconcat 'identity reftex-default-bibliography ",")))))
- (save-buffer)
-
- ;; get a latex file and extract the references
- (org-latex-export-to-latex)
- (find-file texfile)
- (reftex-parse-all)
- (reftex-create-bibtex-file bibfile)
- (save-buffer)
- ;; save results of the references
- (setq results (buffer-string))
-
- ;; kill buffers. these are named by basename, not full path
- (kill-buffer (concat basename ".bib"))
- (kill-buffer (concat basename ".tex"))
- (kill-buffer basename)
-
- (delete-file bibfile)
- (delete-file texfile)
- (delete-file tempname)
-
- ;; Now back to the original org buffer and insert the results
- (switch-to-buffer cb)
- (when (not (string= "" results))
- (save-excursion
- (goto-char (point-max))
- (insert "\n\n")
- (org-insert-heading)
- (insert (format " Bibtex entries
-
-,#+BEGIN_SRC text :tangle %s
-%s
-,#+END_SRC" (concat (file-name-sans-extension (file-name-nondirectory (buffer-file-name))) ".bib") results))))))
-#+END_SRC
-
-** Find bad cite links
-Depending on how you enter citations, you may have citations with no corresponding bibtex entry. This function finds them and gives you a clickable table to navigate to them.
-
-#+BEGIN_SRC emacs-lisp :tangle org-ref.el
-(require 'cl)
-
-(defun index (substring list)
- "return the index of string in a list of strings"
- (let ((i 0)
- (found nil))
- (dolist (arg list i)
- (if (string-match (concat "^" substring "$") arg)
- (progn
- (setq found t)
- (return i)))
- (setq i (+ i 1)))
- ;; return counter if found, otherwise return nil
- (if found i nil)))
-
-
-(defun org-ref-find-bad-citations ()
- "Create a list of citation keys in an org-file that do not have a bibtex entry in the known bibtex files.
-
-Makes a new buffer with clickable links."
- (interactive)
- ;; generate the list of bibtex-keys and cited keys
- (let* ((bibtex-files (org-ref-find-bibliography))
- (bibtex-file-path (mapconcat (lambda (x) (file-name-directory (file-truename x))) bibtex-files ":"))
- (bibtex-keys (mapcar (lambda (x) (car x)) (bibtex-global-key-alist)))
- (bad-citations '()))
-
- (org-element-map (org-element-parse-buffer) 'link
- (lambda (link)
- (let ((plist (nth 1 link)))
- (when (equal (plist-get plist ':type) "cite")
- (dolist (key (org-ref-split-and-strip-string (plist-get plist ':path)) )
- (when (not (index key bibtex-keys))
- (setq bad-citations (append bad-citations
- `(,(format "%s [[elisp:(progn (switch-to-buffer-other-frame \"%s\")(goto-char %s))][not found here]]\n"
- key (buffer-name)(plist-get plist ':begin)))))
- ))))))
-
- (if bad-citations
- (progn
- (switch-to-buffer-other-window "*Missing citations*")
- (org-mode)
- (erase-buffer)
- (insert "* List of bad cite links\n")
- (insert (mapconcat 'identity bad-citations ""))
- ;(setq buffer-read-only t)
- (use-local-map (copy-keymap org-mode-map))
- (local-set-key "q" #'(lambda () (interactive) (kill-buffer))))
-
- (when (get-buffer "*Missing citations*")
- (kill-buffer "*Missing citations*"))
- (message "No bad cite links found"))))
-#+END_SRC
-
-** 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 add it to a hook that updates after every command, including cursor movements.
-
-ref:test citep:test label:rett
-
-#+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 (thing-at-point 'paragraph)))
-
- (goto-char (point-min))
- (when (re-search-forward
- (format "\\label{%s}" label) nil t)
- (throw 'result (thing-at-point 'paragraph)))
-
- (goto-char (point-min))
- (when (re-search-forward
- (format "^#\\+label:\\s-*\\(%s\\)\\b" label) nil t)
- (throw 'result (thing-at-point 'paragraph)))
-
- (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))))))))
-
-(defun org-ref-link-message ()
- "Print a minibuffer message about the link that point is on."
- (interactive)
- (let* ((object (org-element-context))
- (type (org-element-property :type object)))
-
- (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-box "%s" (org-element-property :path object))
- (message (org-ref-get-label-context
- (org-element-property :path object))))
-
- ;; message the count
- ((string= type "label")
- (let ((count (org-ref-count-labels
- (org-element-property :path object))))
- (message (concat
- (number-to-string count)
- " occurence"
- (when (or (= count 0)
- (> count 1))
- "s"))))))))
-
-(when org-ref-show-citation-on-enter
- (add-hook 'post-command-hook 'org-ref-link-message))
-#+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."
- (let* ((object (org-element-context)))
- (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)))
- (goto-char (org-element-property :end object))
- ;; sometimes there are spaces at the end of the link
- ;; this code moves point pack until no spaces are there
- (while (looking-back " ") (backward-char))
- (insert (concat "," (mapconcat 'identity keys ","))))
-
- ;; We are next to a link, and we want to append
- ((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)))))
- (goto-char (org-element-property :end object))
- (while (looking-back " ") (backward-char))
- (insert (concat "," (mapconcat 'identity keys ","))))
-
- ;; insert fresh link
- (t
- (insert
- (concat (if helm-current-prefix-arg
- (ido-completing-read "Type: " org-ref-cite-types)
- 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 ()
- "org-ref function to use helm on the bibliography defined in the org-file."
- (interactive)
- (let ((helm-bibtex-bibliography (org-ref-find-bibliography)))
- (helm-bibtex)))
-
-(require 'helm-bibtex)
-#+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)))
- (save-excursion
- (with-temp-buffer
- (insert-file-contents bibfile)
- (bibtex-search-entry key)
- (org-ref-bib-citation)))))
-
-(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))))
-
-
- (when (file-exists-p pdf-file)
- (add-to-list
- 'candidates
- '("Open pdf" . org-ref-open-pdf-at-point)
- t
- ))
-
- (add-to-list
- 'candidates
- '("Open notes" . org-ref-open-notes-at-point)
- t)
-
- (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
-
-* Build :noexport:
-This code will tangle the elisp code out to org-ref.el and load it.
-
-[[elisp:(progn (org-babel-tangle) (load-file "org-ref.el"))]]