| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375 | ;;; ox-bibtex.el --- Export bibtex fragments;; Copyright (C) 2009-2014 Taru Karttunen;; Author: Taru Karttunen <taruti@taruti.net>;;      Nicolas Goaziou <n dot goaziou at gmail dot com>;; This file is not currently part of GNU Emacs.;; This program is free software; you can redistribute it and/or;; modify it under the terms of the GNU General Public License as;; published by the Free Software Foundation; either version 2, or (at;; your option) any later version.;; This program is distributed in the hope that it will be useful, but;; WITHOUT ANY WARRANTY; without even the implied warranty of;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU;; General Public License for more details.;; You should have received a copy of the GNU General Public License;; along with this program ; see the file COPYING.  If not, write to;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,;; Boston, MA 02111-1307, USA.;;; Commentary:;;;; This is an utility to handle BibTeX export to LaTeX, html and ascii;; exports.  For HTML and ascii it uses the bibtex2html software from:;;;;   http://www.lri.fr/~filliatr/bibtex2html/;;;; For ascii it uses the pandoc software from:;;;;   http://johnmacfarlane.net/pandoc/;;;; It also introduces "cite" syntax for Org links.;;;; The usage is as follows:;;;;   #+BIBLIOGRAPHY: bibfilebasename stylename optional-options;;;; e.g. given foo.bib and using style plain:;;;;   #+BIBLIOGRAPHY: foo plain option:-d;;;; "stylename" can also be "nil", in which case no style will be used.;;;; Optional options are of the form:;;;;   option:-foobar pass '-foobar' to bibtex2html;;;; e.g.,;;;;   option:-d    sort by date;;   option:-a    sort as BibTeX (usually by author) *default*;;   option:-u    unsorted i.e. same order as in .bib file;;   option:-r    reverse the sort;;;; See the bibtex2html man page for more.  Multiple options can be;; combined like:;;;;   option:-d option:-r;;;; Limiting to only the entries cited in the document:;;;;   limit:t;;;; For LaTeX export this simply inserts the lines;;;;   \bibliographystyle{plain};;   \bibliography{foo};;;; into the TeX file when exporting.;;;; For HTML export it:;; 1) converts all \cite{foo} and [[cite:foo]] to links to the;;    bibliography,;; 2) creates a foo.html and foo_bib.html,;; 3) includes the contents of foo.html in the exported HTML file.;;;; For ascii export it:;; 1) converts all \cite{foo} and [[cite:foo]] to links to the;;    bibliography,;; 2) creates a foo.txt and foo_bib.html,;; 3) includes the contents of foo.txt in the exported ascii file.;;;; For LaTeX export it:;; 1) converts all [[cite:foo]] to \cite{foo}.;; Initialization(eval-when-compile (require 'cl))(let ((jump-fn (car (org-remove-if-not #'fboundp '(ebib obe-goto-citation)))))  (org-add-link-type "cite" jump-fn));;; Internal Functions(defun org-bibtex-get-file (keyword)  "Return bibliography file as a string.KEYWORD is a \"BIBLIOGRAPHY\" keyword. If no file is found,return nil instead."  (let ((value (org-element-property :value keyword)))    (and value         (string-match "\\(\\S-+\\)[ \t]+\\(\\S-+\\)\\(.*\\)" value)         (match-string 1 value))))(defun org-bibtex-get-style (keyword)  "Return bibliography style as a string.KEYWORD is a \"BIBLIOGRAPHY\" keyword. If no style is found,return nil instead."  (let ((value (org-element-property :value keyword)))    (and value         (string-match "\\(\\S-+\\)[ \t]+\\(\\S-+\\)\\(.*\\)" value)         (match-string 2 value))))(defun org-bibtex-get-arguments (keyword)  "Return \"bibtex2html\" arguments specified by the user.KEYWORD is a \"BIBLIOGRAPHY\" keyword. Return value is a plistcontaining `:options' and `:limit' properties.  The formercontains a list of strings to be passed as options to\"bibtex2html\" process.  The latter contains a boolean."  (let ((value (org-element-property :value keyword)))    (and value         (string-match "\\(\\S-+\\)[ \t]+\\(\\S-+\\)\\(.*\\)" value)         (let (options limit)           (dolist (arg (org-split-string (match-string 3 value))                        ;; Return value.                        (list :options (nreverse options) :limit limit))             (let* ((s (split-string arg ":"))                    (key (car s))                    (value (nth 1 s)))               (cond ((equal "limit" key)                      (setq limit (not (equal "nil" value))))                     ((equal "option" key) (push value options)))))))))(defun org-bibtex-citation-p (object)  "Non-nil when OBJECT is a citation."  (case (org-element-type object)    (link (equal (org-element-property :type object) "cite"))    (latex-fragment     (string-match "\\`\\\\cite{" (org-element-property :value object)))))(defun org-bibtex-get-citation-key (citation)  "Return key for a given citation, as a string.CITATION is a `latex-fragment' or `link' type object satisfyingto `org-bibtex-citation-p' predicate."  (if (eq (org-element-type citation) 'link)      (org-element-property :path citation)    (let ((value (org-element-property :value citation)))      (and (string-match "\\`\\\\cite{" value)	   (substring value (match-end 0) -1)))));;; Filters(defun org-bibtex-process-bib-files (tree backend info)  "Send each bibliography in parse tree to \"bibtex2html\" process.Return new parse tree."  (when (org-export-derived-backend-p backend 'ascii 'html)    ;; Initialize dynamically scoped variables.  The first one    ;; contain an alist between keyword objects and their HTML    ;; translation.  The second one will contain an alist between    ;; citation keys and names in the output (according to style).    (setq org-bibtex-html-entries-alist nil	  org-bibtex-html-keywords-alist nil)    (org-element-map tree 'keyword      (lambda (keyword)	(when (equal (org-element-property :key keyword) "BIBLIOGRAPHY")	  (let ((arguments (org-bibtex-get-arguments keyword))		(file (org-bibtex-get-file keyword))		temp-file)	    ;; limit is set: collect citations throughout the document	    ;; in TEMP-FILE and pass it to "bibtex2html" as "-citefile"	    ;; argument.	    (when (plist-get arguments :limit)	      (let ((citations		     (org-element-map tree '(latex-fragment link)		       (lambda (object)			 (and (org-bibtex-citation-p object)			      (org-bibtex-get-citation-key object))))))		(with-temp-file (setq temp-file (make-temp-file "ox-bibtex"))		  (insert (mapconcat 'identity citations "\n")))		(setq arguments		      (plist-put arguments				 :options				 (append (plist-get arguments :options)					 (list "-citefile" temp-file))))))	    ;; Call "bibtex2html" on specified file.	    (unless (eq 0 (apply			   'call-process			   (append '("bibtex2html" nil nil nil)				   '("-a" "-nodoc" "-noheader" "-nofooter")				   (let ((style					  (org-not-nil					   (org-bibtex-get-style keyword))))				     (and style (list "--style" style)))				   (plist-get arguments :options)				   (list (concat file ".bib")))))	      (error "Executing bibtex2html failed"))	    (and temp-file (delete-file temp-file))	    ;; Open produced HTML file, and collect Bibtex key names	    (with-temp-buffer	      (insert-file-contents (concat file ".html"))	      ;; Update `org-bibtex-html-entries-alist'.	      (goto-char (point-min))	      (while (re-search-forward		      "a name=\"\\([-_a-zA-Z0-9:]+\\)\">\\(\\w+\\)" nil t)		(push (cons (match-string 1) (match-string 2))		      org-bibtex-html-entries-alist)))	    ;; Open produced HTML file, wrap references within a block and	    ;; return it.	    (with-temp-buffer	      (cond	       ((org-export-derived-backend-p backend 'html)		(insert "<div id=\"bibliography\">\n<h2>References</h2>\n")		(insert-file-contents (concat file ".html"))		(insert "\n</div>"))	       ((org-export-derived-backend-p backend 'ascii)		;; convert HTML references to text w/pandoc		(unless (eq 0 (call-process "pandoc" nil nil nil					    (concat file ".html")					    "-o"					    (concat file ".txt")))		  (error "Executing pandoc failed"))		(insert "References\n==========\n\n")		(insert-file-contents (concat file ".txt"))		(goto-char (point-min))		(while (re-search-forward			"\\[ \\[bib\\][^ ]+ \\(\\]\\||[\n\r]\\)" nil t)		  (replace-match ""))		(goto-char (point-min))		(while (re-search-forward "\\( \\]\\| \\]\\| |\\)" nil t)		  (replace-match ""))		(goto-char (point-min))		(while (re-search-forward "[\n\r]\\([\n\r][\n\r]\\)" nil t)		  (replace-match "\\1"))))	      ;; Update `org-bibtex-html-keywords-alist'.	      (push (cons keyword (buffer-string))		    org-bibtex-html-keywords-alist)))))))  ;; Return parse tree unchanged.  tree)(defun org-bibtex-merge-contiguous-citations (tree backend info)  "Merge all contiguous citation in parse tree.As a side effect, this filter will also turn all \"cite\" linksinto \"\\cite{...}\" LaTeX fragments."  (when (org-export-derived-backend-p backend 'html 'latex 'ascii)    (org-element-map tree '(link latex-fragment)      (lambda (object)	(when (org-bibtex-citation-p object)	  (let ((new-citation (list 'latex-fragment				    (list :value ""					  :post-blank (org-element-property						       :post-blank object)))))	    ;; Insert NEW-CITATION right before OBJECT.	    (org-element-insert-before new-citation object)	    ;; Remove all subsequent contiguous citations from parse	    ;; tree, keeping only their citation key.	    (let ((keys (list (org-bibtex-get-citation-key object)))		  next)	      (while (and (setq next (org-export-get-next-element object info))			  (or (and (stringp next)				   (not (org-string-match-p "\\S-" next)))			      (org-bibtex-citation-p next)))		(unless (stringp next)		  (push (org-bibtex-get-citation-key next) keys))		(org-element-extract-element object)		(setq object next))	      (org-element-extract-element object)	      ;; Eventually merge all keys within NEW-CITATION.  Also	      ;; ensure NEW-CITATION has the same :post-blank property	      ;; as the last citation removed.	      (org-element-put-property	       new-citation	       :post-blank (org-element-property :post-blank object))	      (org-element-put-property	       new-citation	       :value (format "\\cite{%s}"			      (mapconcat 'identity (nreverse keys) ",")))))))))  tree)(eval-after-load 'ox  '(progn (add-to-list 'org-export-filter-parse-tree-functions		       'org-bibtex-process-bib-files)	  (add-to-list 'org-export-filter-parse-tree-functions		       'org-bibtex-merge-contiguous-citations)));;; LaTeX Part(defadvice org-latex-keyword (around bibtex-keyword)  "Translate \"BIBLIOGRAPHY\" keywords into LaTeX syntax.Fallback to `latex' back-end for other keywords."  (let ((keyword (ad-get-arg 0)))    (if (not (equal (org-element-property :key keyword) "BIBLIOGRAPHY"))        ad-do-it      (let ((file (org-bibtex-get-file keyword))            (style (org-not-nil (org-bibtex-get-style keyword))))        (setq ad-return-value              (when file                (concat (and style (format "\\bibliographystyle{%s}\n" style))                        (format "\\bibliography{%s}" file))))))))(ad-activate 'org-latex-keyword);;; HTML Part(defvar org-bibtex-html-entries-alist nil)  ; Dynamically scoped.(defvar org-bibtex-html-keywords-alist nil) ; Dynamically scoped.;;;; Advices(defadvice org-html-keyword (around bibtex-keyword)  "Translate \"BIBLIOGRAPHY\" keywords into HTML syntax.Fallback to `html' back-end for other keywords."  (let ((keyword (ad-get-arg 0)))    (if (not (equal (org-element-property :key keyword) "BIBLIOGRAPHY"))        ad-do-it      (setq ad-return-value            (cdr (assq keyword org-bibtex-html-keywords-alist))))))(defadvice org-html-latex-fragment (around bibtex-citation)  "Translate \"\\cite\" LaTeX fragments into HTML syntax.Fallback to `html' back-end for other keywords."  (let ((fragment (ad-get-arg 0)))    (if (not (org-bibtex-citation-p fragment)) ad-do-it      (setq ad-return-value            (format "[%s]"		    (mapconcat		     (lambda (key)		       (format "<a href=\"#%s\">%s</a>"			       key			       (or (cdr (assoc key org-bibtex-html-entries-alist))				   key)))		     (org-split-string		      (org-bibtex-get-citation-key fragment) ",") ","))))))(ad-activate 'org-html-keyword)(ad-activate 'org-html-latex-fragment);;; Ascii Part(defadvice org-ascii-keyword (around bibtex-keyword)  "Translate \"BIBLIOGRAPHY\" keywords into ascii syntax.Fallback to `ascii' back-end for other keywords."  (let ((keyword (ad-get-arg 0)))    (if (not (equal (org-element-property :key keyword) "BIBLIOGRAPHY"))        ad-do-it      (setq ad-return-value            (cdr (assq keyword org-bibtex-html-keywords-alist))))))(defadvice org-ascii-latex-fragment (around bibtex-citation)  "Translate \"\\cite\" LaTeX fragments into ascii syntax.Fallback to `ascii' back-end for other keywords."  (let ((fragment (ad-get-arg 0)))    (if (not (org-bibtex-citation-p fragment)) ad-do-it      (setq ad-return-value            (format "[%s]"		    (mapconcat		     (lambda (key)		       (or (cdr (assoc key org-bibtex-html-entries-alist))			   key))		     (org-split-string		      (org-bibtex-get-citation-key fragment) ",") ","))))))(ad-activate 'org-ascii-keyword)(ad-activate 'org-ascii-latex-fragment)(provide 'ox-bibtex);;; ox-bibtex.el ends here
 |