ox-bibtex.el 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. ;;; ox-bibtex.el --- Export bibtex fragments
  2. ;; Copyright (C) 2009-2014 Taru Karttunen
  3. ;; Author: Taru Karttunen <taruti@taruti.net>
  4. ;; Nicolas Goaziou <n dot goaziou at gmail dot com>
  5. ;; This file is not currently part of GNU Emacs.
  6. ;; This program is free software; you can redistribute it and/or
  7. ;; modify it under the terms of the GNU General Public License as
  8. ;; published by the Free Software Foundation; either version 2, or (at
  9. ;; your option) any later version.
  10. ;; This program is distributed in the hope that it will be useful, but
  11. ;; WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. ;; General Public License for more details.
  14. ;; You should have received a copy of the GNU General Public License
  15. ;; along with this program ; see the file COPYING. If not, write to
  16. ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  17. ;; Boston, MA 02111-1307, USA.
  18. ;;; Commentary:
  19. ;;
  20. ;; This is an utility to handle BibTeX export to LaTeX, html and ascii
  21. ;; exports. For HTML and ascii it uses the bibtex2html software from:
  22. ;;
  23. ;; http://www.lri.fr/~filliatr/bibtex2html/
  24. ;;
  25. ;; For ascii it uses the pandoc software from:
  26. ;;
  27. ;; http://johnmacfarlane.net/pandoc/
  28. ;;
  29. ;; It also introduces "cite" syntax for Org links.
  30. ;;
  31. ;; The usage is as follows:
  32. ;;
  33. ;; #+BIBLIOGRAPHY: bibfilebasename stylename optional-options
  34. ;;
  35. ;; e.g. given foo.bib and using style plain:
  36. ;;
  37. ;; #+BIBLIOGRAPHY: foo plain option:-d
  38. ;;
  39. ;; "stylename" can also be "nil", in which case no style will be used.
  40. ;;
  41. ;; Optional options are of the form:
  42. ;;
  43. ;; option:-foobar pass '-foobar' to bibtex2html
  44. ;;
  45. ;; e.g.,
  46. ;;
  47. ;; option:-d sort by date
  48. ;; option:-a sort as BibTeX (usually by author) *default*
  49. ;; option:-u unsorted i.e. same order as in .bib file
  50. ;; option:-r reverse the sort
  51. ;;
  52. ;; See the bibtex2html man page for more. Multiple options can be
  53. ;; combined like:
  54. ;;
  55. ;; option:-d option:-r
  56. ;;
  57. ;; Limiting to only the entries cited in the document:
  58. ;;
  59. ;; limit:t
  60. ;;
  61. ;; For LaTeX export this simply inserts the lines
  62. ;;
  63. ;; \bibliographystyle{plain}
  64. ;; \bibliography{foo}
  65. ;;
  66. ;; into the TeX file when exporting.
  67. ;;
  68. ;; For HTML export it:
  69. ;; 1) converts all \cite{foo} and [[cite:foo]] to links to the
  70. ;; bibliography,
  71. ;; 2) creates a foo.html and foo_bib.html,
  72. ;; 3) includes the contents of foo.html in the exported HTML file.
  73. ;;
  74. ;; For ascii export it:
  75. ;; 1) converts all \cite{foo} and [[cite:foo]] to links to the
  76. ;; bibliography,
  77. ;; 2) creates a foo.txt and foo_bib.html,
  78. ;; 3) includes the contents of foo.txt in the exported ascii file.
  79. ;;
  80. ;; For LaTeX export it:
  81. ;; 1) converts all [[cite:foo]] to \cite{foo}.
  82. ;; Initialization
  83. (eval-when-compile (require 'cl))
  84. (let ((jump-fn (car (org-remove-if-not #'fboundp '(ebib obe-goto-citation)))))
  85. (org-add-link-type "cite" jump-fn))
  86. ;;; Internal Functions
  87. (defun org-bibtex-get-file (keyword)
  88. "Return bibliography file as a string.
  89. KEYWORD is a \"BIBLIOGRAPHY\" keyword. If no file is found,
  90. return nil instead."
  91. (let ((value (org-element-property :value keyword)))
  92. (and value
  93. (string-match "\\(\\S-+\\)[ \t]+\\(\\S-+\\)\\(.*\\)" value)
  94. (match-string 1 value))))
  95. (defun org-bibtex-get-style (keyword)
  96. "Return bibliography style as a string.
  97. KEYWORD is a \"BIBLIOGRAPHY\" keyword. If no style is found,
  98. return nil instead."
  99. (let ((value (org-element-property :value keyword)))
  100. (and value
  101. (string-match "\\(\\S-+\\)[ \t]+\\(\\S-+\\)\\(.*\\)" value)
  102. (match-string 2 value))))
  103. (defun org-bibtex-get-arguments (keyword)
  104. "Return \"bibtex2html\" arguments specified by the user.
  105. KEYWORD is a \"BIBLIOGRAPHY\" keyword. Return value is a plist
  106. containing `:options' and `:limit' properties. The former
  107. contains a list of strings to be passed as options to
  108. \"bibtex2html\" process. The latter contains a boolean."
  109. (let ((value (org-element-property :value keyword)))
  110. (and value
  111. (string-match "\\(\\S-+\\)[ \t]+\\(\\S-+\\)\\(.*\\)" value)
  112. (let (options limit)
  113. (dolist (arg (org-split-string (match-string 3 value))
  114. ;; Return value.
  115. (list :options (nreverse options) :limit limit))
  116. (let* ((s (split-string arg ":"))
  117. (key (car s))
  118. (value (nth 1 s)))
  119. (cond ((equal "limit" key)
  120. (setq limit (not (equal "nil" value))))
  121. ((equal "option" key) (push value options)))))))))
  122. (defun org-bibtex-citation-p (object)
  123. "Non-nil when OBJECT is a citation."
  124. (case (org-element-type object)
  125. (link (equal (org-element-property :type object) "cite"))
  126. (latex-fragment
  127. (string-match "\\`\\\\cite{" (org-element-property :value object)))))
  128. (defun org-bibtex-get-citation-key (citation)
  129. "Return key for a given citation, as a string.
  130. CITATION is a `latex-fragment' or `link' type object satisfying
  131. to `org-bibtex-citation-p' predicate."
  132. (if (eq (org-element-type citation) 'link)
  133. (org-element-property :path citation)
  134. (let ((value (org-element-property :value citation)))
  135. (and (string-match "\\`\\\\cite{" value)
  136. (substring value (match-end 0) -1)))))
  137. ;;; Filters
  138. (defun org-bibtex-process-bib-files (tree backend info)
  139. "Send each bibliography in parse tree to \"bibtex2html\" process.
  140. Return new parse tree."
  141. (when (org-export-derived-backend-p backend 'ascii 'html)
  142. ;; Initialize dynamically scoped variables. The first one
  143. ;; contain an alist between keyword objects and their HTML
  144. ;; translation. The second one will contain an alist between
  145. ;; citation keys and names in the output (according to style).
  146. (setq org-bibtex-html-entries-alist nil
  147. org-bibtex-html-keywords-alist nil)
  148. (org-element-map tree 'keyword
  149. (lambda (keyword)
  150. (when (equal (org-element-property :key keyword) "BIBLIOGRAPHY")
  151. (let ((arguments (org-bibtex-get-arguments keyword))
  152. (file (org-bibtex-get-file keyword))
  153. temp-file)
  154. ;; limit is set: collect citations throughout the document
  155. ;; in TEMP-FILE and pass it to "bibtex2html" as "-citefile"
  156. ;; argument.
  157. (when (plist-get arguments :limit)
  158. (let ((citations
  159. (org-element-map tree '(latex-fragment link)
  160. (lambda (object)
  161. (and (org-bibtex-citation-p object)
  162. (org-bibtex-get-citation-key object))))))
  163. (with-temp-file (setq temp-file (make-temp-file "ox-bibtex"))
  164. (insert (mapconcat 'identity citations "\n")))
  165. (setq arguments
  166. (plist-put arguments
  167. :options
  168. (append (plist-get arguments :options)
  169. (list "-citefile" temp-file))))))
  170. ;; Call "bibtex2html" on specified file.
  171. (unless (eq 0 (apply
  172. 'call-process
  173. (append '("bibtex2html" nil nil nil)
  174. '("-a" "-nodoc" "-noheader" "-nofooter")
  175. (let ((style
  176. (org-not-nil
  177. (org-bibtex-get-style keyword))))
  178. (and style (list "--style" style)))
  179. (plist-get arguments :options)
  180. (list (concat file ".bib")))))
  181. (error "Executing bibtex2html failed"))
  182. (and temp-file (delete-file temp-file))
  183. ;; Open produced HTML file, and collect Bibtex key names
  184. (with-temp-buffer
  185. (insert-file-contents (concat file ".html"))
  186. ;; Update `org-bibtex-html-entries-alist'.
  187. (goto-char (point-min))
  188. (while (re-search-forward
  189. "a name=\"\\([-_a-zA-Z0-9:]+\\)\">\\(\\w+\\)" nil t)
  190. (push (cons (match-string 1) (match-string 2))
  191. org-bibtex-html-entries-alist)))
  192. ;; Open produced HTML file, wrap references within a block and
  193. ;; return it.
  194. (with-temp-buffer
  195. (cond
  196. ((org-export-derived-backend-p backend 'html)
  197. (insert "<div id=\"bibliography\">\n<h2>References</h2>\n")
  198. (insert-file-contents (concat file ".html"))
  199. (insert "\n</div>"))
  200. ((org-export-derived-backend-p backend 'ascii)
  201. ;; convert HTML references to text w/pandoc
  202. (unless (eq 0 (call-process "pandoc" nil nil nil
  203. (concat file ".html")
  204. "-o"
  205. (concat file ".txt")))
  206. (error "Executing pandoc failed"))
  207. (insert "References\n==========\n\n")
  208. (insert-file-contents (concat file ".txt"))
  209. (goto-char (point-min))
  210. (while (re-search-forward
  211. "\\[ \\[bib\\][^ ]+ \\(\\]\\||[\n\r]\\)" nil t)
  212. (replace-match ""))
  213. (goto-char (point-min))
  214. (while (re-search-forward "\\( \\]\\| \\]\\| |\\)" nil t)
  215. (replace-match ""))
  216. (goto-char (point-min))
  217. (while (re-search-forward "[\n\r]\\([\n\r][\n\r]\\)" nil t)
  218. (replace-match "\\1"))))
  219. ;; Update `org-bibtex-html-keywords-alist'.
  220. (push (cons keyword (buffer-string))
  221. org-bibtex-html-keywords-alist)))))))
  222. ;; Return parse tree unchanged.
  223. tree)
  224. (defun org-bibtex-merge-contiguous-citations (tree backend info)
  225. "Merge all contiguous citation in parse tree.
  226. As a side effect, this filter will also turn all \"cite\" links
  227. into \"\\cite{...}\" LaTeX fragments."
  228. (when (org-export-derived-backend-p backend 'html 'latex 'ascii)
  229. (org-element-map tree '(link latex-fragment)
  230. (lambda (object)
  231. (when (org-bibtex-citation-p object)
  232. (let ((new-citation (list 'latex-fragment
  233. (list :value ""
  234. :post-blank (org-element-property
  235. :post-blank object)))))
  236. ;; Insert NEW-CITATION right before OBJECT.
  237. (org-element-insert-before new-citation object)
  238. ;; Remove all subsequent contiguous citations from parse
  239. ;; tree, keeping only their citation key.
  240. (let ((keys (list (org-bibtex-get-citation-key object)))
  241. next)
  242. (while (and (setq next (org-export-get-next-element object info))
  243. (or (and (stringp next)
  244. (not (org-string-match-p "\\S-" next)))
  245. (org-bibtex-citation-p next)))
  246. (unless (stringp next)
  247. (push (org-bibtex-get-citation-key next) keys))
  248. (org-element-extract-element object)
  249. (setq object next))
  250. (org-element-extract-element object)
  251. ;; Eventually merge all keys within NEW-CITATION. Also
  252. ;; ensure NEW-CITATION has the same :post-blank property
  253. ;; as the last citation removed.
  254. (org-element-put-property
  255. new-citation
  256. :post-blank (org-element-property :post-blank object))
  257. (org-element-put-property
  258. new-citation
  259. :value (format "\\cite{%s}"
  260. (mapconcat 'identity (nreverse keys) ",")))))))))
  261. tree)
  262. (eval-after-load 'ox
  263. '(progn (add-to-list 'org-export-filter-parse-tree-functions
  264. 'org-bibtex-process-bib-files)
  265. (add-to-list 'org-export-filter-parse-tree-functions
  266. 'org-bibtex-merge-contiguous-citations)))
  267. ;;; LaTeX Part
  268. (defadvice org-latex-keyword (around bibtex-keyword)
  269. "Translate \"BIBLIOGRAPHY\" keywords into LaTeX syntax.
  270. Fallback to `latex' back-end for other keywords."
  271. (let ((keyword (ad-get-arg 0)))
  272. (if (not (equal (org-element-property :key keyword) "BIBLIOGRAPHY"))
  273. ad-do-it
  274. (let ((file (org-bibtex-get-file keyword))
  275. (style (org-not-nil (org-bibtex-get-style keyword))))
  276. (setq ad-return-value
  277. (when file
  278. (concat (and style (format "\\bibliographystyle{%s}\n" style))
  279. (format "\\bibliography{%s}" file))))))))
  280. (ad-activate 'org-latex-keyword)
  281. ;;; HTML Part
  282. (defvar org-bibtex-html-entries-alist nil) ; Dynamically scoped.
  283. (defvar org-bibtex-html-keywords-alist nil) ; Dynamically scoped.
  284. ;;;; Advices
  285. (defadvice org-html-keyword (around bibtex-keyword)
  286. "Translate \"BIBLIOGRAPHY\" keywords into HTML syntax.
  287. Fallback to `html' back-end for other keywords."
  288. (let ((keyword (ad-get-arg 0)))
  289. (if (not (equal (org-element-property :key keyword) "BIBLIOGRAPHY"))
  290. ad-do-it
  291. (setq ad-return-value
  292. (cdr (assq keyword org-bibtex-html-keywords-alist))))))
  293. (defadvice org-html-latex-fragment (around bibtex-citation)
  294. "Translate \"\\cite\" LaTeX fragments into HTML syntax.
  295. Fallback to `html' back-end for other keywords."
  296. (let ((fragment (ad-get-arg 0)))
  297. (if (not (org-bibtex-citation-p fragment)) ad-do-it
  298. (setq ad-return-value
  299. (format "[%s]"
  300. (mapconcat
  301. (lambda (key)
  302. (format "<a href=\"#%s\">%s</a>"
  303. key
  304. (or (cdr (assoc key org-bibtex-html-entries-alist))
  305. key)))
  306. (org-split-string
  307. (org-bibtex-get-citation-key fragment) ",") ","))))))
  308. (ad-activate 'org-html-keyword)
  309. (ad-activate 'org-html-latex-fragment)
  310. ;;; Ascii Part
  311. (defadvice org-ascii-keyword (around bibtex-keyword)
  312. "Translate \"BIBLIOGRAPHY\" keywords into ascii syntax.
  313. Fallback to `ascii' back-end for other keywords."
  314. (let ((keyword (ad-get-arg 0)))
  315. (if (not (equal (org-element-property :key keyword) "BIBLIOGRAPHY"))
  316. ad-do-it
  317. (setq ad-return-value
  318. (cdr (assq keyword org-bibtex-html-keywords-alist))))))
  319. (defadvice org-ascii-latex-fragment (around bibtex-citation)
  320. "Translate \"\\cite\" LaTeX fragments into ascii syntax.
  321. Fallback to `ascii' back-end for other keywords."
  322. (let ((fragment (ad-get-arg 0)))
  323. (if (not (org-bibtex-citation-p fragment)) ad-do-it
  324. (setq ad-return-value
  325. (format "[%s]"
  326. (mapconcat
  327. (lambda (key)
  328. (or (cdr (assoc key org-bibtex-html-entries-alist))
  329. key))
  330. (org-split-string
  331. (org-bibtex-get-citation-key fragment) ",") ","))))))
  332. (ad-activate 'org-ascii-keyword)
  333. (ad-activate 'org-ascii-latex-fragment)
  334. (provide 'ox-bibtex)
  335. ;;; ox-bibtex.el ends here