>From b3a6660058fadb2a67b977c553ded414f7a6a657 Mon Sep 17 00:00:00 2001 From: Jambunathan K Date: Wed, 24 Jul 2013 19:25:02 +0530 Subject: [PATCH 4/4] ox-odt: Add support for JabRef * contrib/lisp/ox-jabref.el: New file. * lisp/org.el (org-modules): Add ox-jabref. * etc/styles/OrgOdtStyles.xml (Bibliography_20_Heading) (Bibliography, OrgBibliographyList): New styles. * lisp/ox-odt.el (org-export-define-backend): New non-standard element `citation-reference'. Register `org-odt--translate-cite-fragments'. (org-odt--translate-cite-fragments): New filter. (org-odt-citation-transcoders): New user option. (org-odt-citation-reference, org-odt-citation-reference/numbered): Stock transcoders for `citation-reference' elements. (org-odt-keyword): Handle BIBLIOGRAPHY. (org-odt--export-wrap): Make the condition case debuggable. NOTE: Review all the above changes once ox.el provides standard tools for handling citaitons. ---------------------------------------------------------------- To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to this software to the public domain worldwide. This software is distributed without any warranty. You should have received a copy of the CC0 Public Domain Dedication along with this software. If not, see . ---------------------------------------------------------------- --- contrib/lisp/ox-jabref.el | 637 +++++++++++++++++++++++++++++++++++++++++++ etc/styles/OrgOdtStyles.xml | 41 +++ lisp/org.el | 1 + lisp/ox-odt.el | 88 ++++++- 4 files changed, 762 insertions(+), 5 deletions(-) create mode 100644 contrib/lisp/ox-jabref.el diff --git a/contrib/lisp/ox-jabref.el b/contrib/lisp/ox-jabref.el new file mode 100644 index 0000000..2665dad --- /dev/null +++ b/contrib/lisp/ox-jabref.el @@ -0,0 +1,637 @@ +;;; ox-jabref.el --- JabRef Citation Processor for Orgmode + +;; Copyright (C) 2013 Jambunathan K + +;; Author: Jambunathan K +;; Keywords: outlines, hypermedia, calendar, wp +;; Homepage: http://orgmode.org +;; Version: 8.0.6 + +;;; Commentary: + +;;;; Quick start guide: +;; +;; 1. Install [[http://jabref.sourceforge.net/][JabRef]] +;; +;; This module is tested with version JabRef-2.9.2.jar. +;; +;; 2. Install the JabRef plugin [[http://repo.or.cz/w/JabRefChicagoForOrgmode.git/blob_plain/HEAD:/net.sf.jabref.export.Chicago.ODF(English)-1.2.jar][Chicago Export filters for Org-mode]]. +;; +;; 3. Configure ox-jabref.el +;; +;; #+BEGIN_EXAMPLE +;; M-x customize-group RET org-jabref RET +;; #+END_EXAMPLE +;; +;; Review the settings. +;; +;; 4. Configure ox-odt.el +;; +;; #+BEGIN_EXAMPLE +;; M-x customize-variable RET org-jabref-odt-citation-transcoders RET +;; #+END_EXAMPLE +;; +;; Following settings are recommended. +;; +;; 1. No citation support +;; +;; #+BEGIN_SRC emacs-lisp +;; (setq org-jabref-odt-citation-transcoders +;; '(org-odt-latex-fragment . ignore)) +;; #+END_SRC +;; +;; This is the default setting. +;; +;; - #+BIBLIOGRAPHY is ignored. +;; - \cite{} directives are typeset as plain text. + +;; 2. Numeric Citations +;; +;; #+BEGIN_SRC emacs-lisp +;; (setq org-jabref-odt-citation-transcoders +;; '(org-odt-citation-reference/numbered +;; . org-jabref-odt-bibliography/numbered)) +;; #+END_SRC +;; +;; - #+BIBLIOGRAPHY is replaced with numerical listing of +;; Bibliographic entries. The listing includes only cited keys +;; and is sorted on the order in which the cite keys are seen in +;; the Org file. +;; +;; - \cite{} directives are replaced with numeric links to the +;; associated Bibliographic entry. +;; +;; 3. Unnumbered (or Text) Citations with Filtered Bibliography +;; +;; #+BEGIN_SRC emacs-lisp +;; (setq org-jabref-odt-citation-transcoders +;; '(org-jabref-odt-citation-reference/text +;; . org-jabref-odt-bibliography/filtered)) +;; #+END_SRC +;; +;; - #+BIBLIOGRAPHY is replaced with listing of Bibliographic +;; entries. The listing is limited to just the cited keys. The +;; listing is sorted based on the order chosen by JabRef engine. +;; +;; - \cite{} directives are replaced with textual links to the +;; associated Bibliographic entry. +;; +;; 4. Unnumbered (or Text) Citations with Filtered Bibliography +;; +;; #+BEGIN_SRC emacs-lisp +;; (setq org-jabref-odt-citation-transcoders +;; '(org-jabref-odt-citation-reference/text +;; . org-jabref-odt-bibliography/unfiltered)) +;; #+END_SRC +;; +;; - #+BIBLIOGRAPHY is replaced with listing of *all* Bibliographic +;; entries. The listing is limited to just the cited keys. The +;; listing is sorted based on the order chosen by JabRef engine. +;; +;; - \cite{} directives are replaced with textual links to the +;; associated Bibliographic entry. +;; +;; 5. Add the following line to your Org file and export. +;; +;; #+BEGIN_SRC org +;; ,#+BIBLIOGRAPHY: MyLibrary.bib +;; #+END_SRC + +;;;; Developer (or Implementation) notes +;; +;; The current #+BIBLIOGRAPHY is defined in contrib/lisp/ox-bibtex.el. +;; The syntax defined therein, is specific to a particular Citation +;; Processor (i.e., bibtex2html) and cannot be expected to be honored +;; by all backends AND citation processors[fn:1]. +;; +;; 1. So having a "style" specification in a keyword line that is +;; shared across all backends is absurd.[fn:2][fn:3]. +;; +;; 2. It is unclear how well a "limit: " option can be honored by +;; *ALL* citation processors. +;; +;; To keep things simple (and flexible), ox-jabref.el resorts to the +;; following: +;; +;; 1. *Always* use the first found style registered for the current +;; backend in `org-jabref-export-formats' +;; +;; 2. "Limit"-ed (or non-"limit"-ed) export of Bibliographic entries +;; can be achieved by using a different transcoder. See "Quick +;; start guide" above. +;; +;; Footnotes +;; --------- +;; +;; [fn:1] Note that the same Citation Processor (for example, JabRef) +;; can be used for catering to *both* HTML, ODT and even ASCII +;; backends. +;; +;; [fn:2] *If* one settles for Org-wide styles, a possible translation +;; from Org-specific style to Citation-specific style needs to be done +;; by each backend. This is the sole purpose of +;; `org-jabref-export-formats'. +;; +;; Having an Org-wide styles is well-neigh impossible. In that case, +;; the best option is to settle for a specification like +;; +;; #+ATTR_HTML: :bib2html-style "plain" +;; #+ATTR_ODT: :jabref-style "Chicago (author-date)" +;; #+BIBLIOGRAPHY: MyLibrary.bib +;; +;; Note the keywords in #+ATTR_BACKEND lines are prefixed with the +;; Citation Processor. This is important in light of earlier comments +;; [fn:1]. +;; +;;; Code: + +(require 'ox) +(require 'ox-odt) + +;;; User Configuration Options. + +(defgroup org-jabref nil + "Options for processing citations via JabRef." + :tag "Org Jabref" + :group 'org-export) + +(defcustom org-jabref-command '("java" "-jar" "JabRef-2.9.2.jar" "-n" "true") + "Jabref program." + :type '(choice + (const :tag "Not configured" nil) + (repeat string)) + :group 'org-jabref + :version "24.4") + +(defcustom org-jabref-export-formats + '(("odt" + ("Chicago Manual of Style (author-date)" + :in-text "chicago.ODF.text" :bibliography "chicago.ODF.reference"))) + "JabRef export formats for various backends. +Each element in this list is of the form: + + \(EXPORT-BACKEND-NAME . BACKEND-STYLE-FITLERS\) + +BACKEND-STYLE-FILTERS is of the form: + + \(CITATION-STYLE . EXPORT-FORMATS-PLIST\) + +EXPORT-FORMATS-PLIST is property list with two well-known +properties - `:in-text' and `:bibliography'. The values +of these properties are the export formats registered with +JabRef. + +A typical value for this variable could be: + + '((\"odt\" + (\"default\" :in-text \"chicago.ODF.text\" + :bibliography \"chicago.ODF.reference\")) + (\"html\" + (\"default\" :bibliography \"html\") + (\"simple\" :bibliography \"simplehtml\"))) + +For a list of export formats registered with JabRef use: + + java -jar JabRef-2.9.2.jar -n true -h." + :group 'org-jabref + :version "24.4" + :type '(alist :key-type (string :tag "Export backend") + :options ("odt" "html") + :value-type + (alist :key-type (string :tag "Citation style") + :options ("Chicago Manual of Style (author-date)") + :value-type + (plist :tag "export formats" + :value-type (string :tag "export format") + :options (:in-text + :bibliography))))) + +(defcustom org-jabref-export-formats + '(("odt" + ("Chicago Manual of Style (author-date)" + :in-text "chicago.ODF.text" :bibliography "chicago.ODF.reference"))) + "JabRef export formats for various backends. +Each element in this list is of the form: + + \(EXPORT-BACKEND-NAME . BACKEND-STYLE-FITLERS\) + +BACKEND-STYLE-FILTERS is of the form: + + \(CITATION-STYLE . EXPORT-FORMATS-PLIST\) + +EXPORT-FORMATS-PLIST is property list with two well-known +properties - `:in-text' and `:bibliography'. The values +of these properties are the export formats registered with +JabRef. + +A typical value for this variable could be: + + '((\"odt\" + (\"default\" :in-text \"chicago.ODF.text\" + :bibliography \"chicago.ODF.reference\")) + (\"html\" + (\"default\" :bibliography \"html\") + (\"simple\" :bibliography \"simplehtml\"))) + +For a list of export formats registered with JabRef use: + + java -jar JabRef-2.9.2.jar -n true -h." + :group 'org-jabref + :version "24.4" + :type '(alist :key-type (string :tag "Export backend") + :options ("odt" "html") + :value-type + (alist :key-type (string :tag "Citation style") + :options ("Chicago Manual of Style (author-date)") + :value-type + (plist :tag "export formats" + :value-type (string :tag "export format") + :options (:in-text + :bibliography))))) + +(defcustom org-jabref-odt-citation-transcoders + '(org-odt-citation-reference/numbered . org-jabref-odt-bibliography/numbered) + "Transcoders to handle citations. +Use CAR as the transcoder for CITATION-REFERENCE elements. Use +CDR as the transcoder for BIBLIOGRAPHY. See +`org-odt--translate-cite-fragments'. + +For full citation support, install the required Citation +Processor (JabRef, for example) and turn on the associated Elisp +module in `org-modules'." + :type `(cons + (radio :tag ,(format "%-35s" "Transcoder for \\cite{ } fragments") + (function-item :doc "Export Verbatim" + org-odt-latex-fragment) + (function-item :doc "(JabRef) Enumerate" + org-odt-citation-reference/numbered) + (function-item :doc "(JabRef) Text Description" + org-jabref-odt-citation-reference/text) + function) + (radio :tag ,(format "%-35s" "Transcoder for Bibliography") + (function-item :doc "Strip Bibliography" + ignore) + (function-item :doc "(JabRef) Enumerate, only cited entries, sort by reference" + org-jabref-odt-bibliography/numbered) + (function-item :doc "(JabRef) Only cited entries, sort by reference" + org-jabref-odt-bibliography/unnumbered) + (function-item :doc "(JabRef) Only cited entries, sort by application order" + org-jabref-odt-bibliography/filtered) + (function-item :doc "(JabRef) Full bibliography, sort by application order" + org-jabref-odt-bibliography/unfiltered) + function)) + :group 'org-export-odt + :version "24.1") + + + +;;; Loading and Unloaing + +(defvar org-jabref--stock-odt-backend + (org-export-get-backend 'odt) + "Backend definition of stock ODT exporter.") + +(defvar org-jabref--enhanced-odt-backend + (let* (;; Copy over the stock backend. + (enhanced-backend (copy-tree org-jabref--stock-odt-backend t))) + ;; Override default citation transcoders with our own. + (setf (org-export-backend-transcoders enhanced-backend) + (append + '((keyword . org-jabref-odt-keyword) + (citation-reference . org-jabref-odt-citation-reference)) + (org-export-backend-transcoders org-jabref--stock-odt-backend))) + ;; Modify the menu description. + (let ((menu (org-export-backend-menu enhanced-backend))) + (setf (cadr menu) (concat (cadr menu) " (With Jabref Processing)"))) + ;; Replace the existing ODT backend. + (org-export-register-backend enhanced-backend) + ;; Return the enhanced backend. + enhanced-backend) + "Backend definition of ODT exporter with JabRef processing.") + +(defun ox-jabref-unload-function () + "Restore the stock ODT backend." + (prog1 nil + (org-export-register-backend org-jabref--stock-odt-backend) + (message "ox-jabref: Unloaded"))) + +;;; Internal functions + +(defun org-jabref--read-bibliography-attribute (info property) + "Return value of PROPERTY of #+BIBLIOGRAPHY keyword. +INFO is a plist holding contextual information for purposes of +export. PROPERTY is one of `:bib-file' or `:citation-style'. If +it is neither, treat is as one of the properties in +#+ATTR_BACKEND attribute of #+BIBLIOGRAPHY keyword, where BACKEND +is the current export backend." + (let* ((data (plist-get info :parse-tree)) + (bibliography (org-element-map data 'keyword + (lambda (keyword) + (let ((key (org-element-property :key keyword))) + (and (string= (upcase key) "BIBLIOGRAPHY") + keyword))) + info 'first-match))) + (cond + ((memq property '(:bib-file :citation-style)) + (let* ((value (org-element-property :value bibliography)) + (values (split-string value)) + (attributes (list :bib-file + (let ((bib-file (nth 0 values))) + (concat (file-name-sans-extension bib-file) + ".bib")) + :citation-style (nth 1 values)))) + (plist-get attributes property))) + (t + (let ((attribute (intern (format ":attr_%s" (plist-get info :backend))))) + (org-export-read-attribute attribute bibliography property)))))) + +(defun org-jabref--get-export-format (info op) + "Return the EXPORT-FORMAT configured for operation OP. +INFO is a plist holding contextual information. OP can be one of +`:in-text' or `:bibliography'. Return EXPORT-FORMAT is +that is registered for the current export backend. See +`org-jabref-export-formats'." + (let* ((backend (plist-get info :back-end)) + (backend-name (symbol-name (org-export-backend-name backend))) + (styles-alist (assoc-default backend-name org-jabref-export-formats)) + ;; FIXME: Ignore the "style" entry in "#+BIBLIOGRAPHY" line. + ;; Just go with the first registered style for this backend + ;; in `org-jabref-export-formats'. + + ;; (citation-style (org-jabref--read-bibliography-attribute + ;; info :citation-style)) + (citation-style (caar styles-alist)) + ;; Get JabRef export format that match this backend and + ;; citation-style. + (export-formats-plist (assoc-default citation-style styles-alist))) + (if (null op) export-formats-plist + (plist-get export-formats-plist op)))) + +(defun org-jabref--run-cmd (&rest args) + "Run JabRef command with ARGS. +Append ARGS to `org-jabref-command' and use `call-process'." + (let ((cmd (append org-jabref-command args))) + (let (exitcode err-string) + (message "Running %s" (mapconcat 'identity cmd " ")) + (setq err-string + (with-output-to-string + (setq exitcode + (apply 'call-process (car cmd) + nil standard-output nil (cdr cmd))))) + (or (zerop exitcode) + (error (format "JabRef command failed with error (%s)" + err-string)))))) + +(defun org-jabref--create-filtered-bibfile (bib-file cite-keys) + "Truncate BIB-FILE so that it contains only CITE-KEYS. +Return name of the newly created bib file. + +Specifically, + + - Create a temporary auxiliary file FILTERED.AUX file which + contains just the CITE-KEYS + + - Run the following command (for example) + + jabref -n true -a FILTERED.AUX,FILTERED.BIB BIB-FILE + + - Return FILTERED.BIB." + + (let* ((aux-file (make-temp-file "jabref" nil ".aux")) + (filtered-bib-file (concat (file-name-sans-extension aux-file) ".bib"))) + ;; Create an .aux file out of CITE-KEYS. + (with-current-buffer (find-file-noselect aux-file) + (insert (mapconcat (lambda (cite-key) + (format "\\citation{%s}" cite-key)) + cite-keys "\n")) + (save-buffer 0)) + ;; Create a filtered bib file out of the aux file. + (org-jabref--run-cmd "-a" (concat aux-file "," filtered-bib-file) bib-file) + ;; Delete aux file. + (delete-file aux-file) + ;; Return filtered bib file. + filtered-bib-file)) + +;;;; Export a BIB file, enbloc + +(defun org-jabref-export-bib-file (bib-file export-format) + "Export BIB-FILE to EXPORT-FORMAT. +Return the resulting XML as string. Specifically, + + - Run the following command (for example) + + jabref -n true -o OUT.XML,EXPORT-FORMAT BIB-FILE + + - Return contents of OUT.XML as a string." + (when (and bib-file (file-readable-p bib-file) export-format) + (with-demoted-errors + (let* ((xml-file (make-temp-file "jabref-" nil ".xml"))) + ;; Export the Citation to it's XML representation. + (org-jabref--run-cmd "-o" (concat xml-file "," export-format) bib-file) + ;; Return the XML string. + (prog1 (with-temp-buffer + (insert-file-contents xml-file) + (buffer-string)) + ;; Delete temporary xml file. + (delete-file xml-file)))))) + +(defun org-jabref-export-bib-file-with-filtering (bib-file cite-keys + export-format) + "Export BIB-FILE to EXPORT-FORMAT, but limit output to just the CITE-KEYS. +Use `org-jabref--create-filtered-bibfile' and `org-jabref-export-bib-file'." + (when (and bib-file (file-readable-p bib-file) cite-keys export-format) + (let ((filtered-bib-file (org-jabref--create-filtered-bibfile bib-file + cite-keys))) + (prog1 (org-jabref-export-bib-file filtered-bib-file export-format) + (delete-file filtered-bib-file))))) + +;;;; Export a CITE-KEY + +(defun org-jabref-export-cite-key (bib-file cite-key export-format) + "Export CITE-KEY from BIB-FILE to EXPORT-FORMAT. +Return the XML representation as a string. Specifically, + + - Run the following command (for example) + + jabref -n true -m CITE-KEY,OUT.XML,EXPORT-FORMAT BIB-FILE + + - Return contents of OUT.XML as a string." + (when (and bib-file (file-readable-p bib-file) cite-key export-format) + (with-demoted-errors + (let* ((xml-file (file-name-nondirectory (make-temp-file "jabref-" nil + ".xml")))) + ;; Export the Citation to it's XML representation. + (org-jabref--run-cmd "-m" (format "%s,%s,%s" cite-key xml-file + export-format) bib-file) + ;; Return the XML string. + (prog1 (with-temp-buffer + (insert-file-contents xml-file) + (buffer-string)) + ;; Delete temporary xml file. + (delete-file xml-file)))))) + + +;;; Transcoders + +;;;; Bibliography + +(defun org-jabref-odt-keyword (keyword contents info) + "Transcode a KEYWORD element from Org to ODT. +CONTENTS is nil. INFO is a plist holding contextual information. + +If KEYWORD is a BIBLIOGRAPHY element, use the transcoder +specified in `org-jabref-odt-citation-transcoders'. If no such +transcoder exists, return nil." + (let ((key (org-element-property :key keyword)) + (value (org-element-property :value keyword))) + (cond + ;; Handle BIBLIOGRAPHY code. + ((string= key "BIBLIOGRAPHY") + (let* ((transcoder (cdr org-jabref-odt-citation-transcoders))) + (when (and transcoder (fboundp transcoder)) + (funcall transcoder keyword contents info)))) + ;; Keyword is other than BIBLIOGRAPHY. Use the stock transcoder. + (t (let ((transcoder (assoc-default 'keyword (org-export-backend-transcoders + org-jabref--stock-odt-backend)))) + (funcall transcoder keyword contents info)))))) + + +;;;; Bibliography :: Un-numbered + +;;;###autoload +(defun org-jabref-odt-bibliography/unnumbered (bibliography contents info) + "Transcode a BIBLIOGRAPHY element from Org to ODT. +CONTENTS is nil. INFO is a plist holding contextual information. + +Export each CITE-KEY in the parse tree through `:bibliography' +EXPORT-FORMAT. Return the concatenated result, after adding some +separators." + (let* ((bib-file (org-jabref--read-bibliography-attribute info :bib-file)) + (cite-keys (mapcar 'car (plist-get info :citations-alist))) + (export-format (org-jabref--get-export-format info :bibliography))) + (format "\n%s\n" + "OrgIndexSection" + "Bibliography" + (concat (format "\n%s" + "Bibliography_20_Heading" "References") + (mapconcat + (lambda (cite-key) + (message "Generating BIBLIOGRAPHY entry for cite-key (%s)..." + cite-key) + (org-jabref-export-cite-key bib-file cite-key + export-format)) + cite-keys "\n"))))) + +;;;; Bibliography :: Numbered + +;;;###autoload +(defun org-jabref-odt-bibliography/numbered (bibliography contents info) + "Transcode a BIBLIOGRAPHY element from Org to ODT. +CONTENTS is nil. INFO is a plist holding contextual information. + +Export each CITE-KEY in the parse tree through `:bibliography' +EXPORT-FORMAT. Enclose the entries in a numbered list and return +the result." + (let* ((bib-file (org-jabref--read-bibliography-attribute info :bib-file)) + ;; Reverse the entries in `:citation-alist' so that CITE-KEYs + ;; are sorted based on their order of occurrence in the Org + ;; file. + (cite-keys (reverse (mapcar 'car (plist-get info :citations-alist)))) + (export-format (org-jabref--get-export-format info :bibliography))) + ;; Enclose Bibliography in it's own section. + (format + "\n%s\n" + "OrgIndexSection" + "Bibliography" + (concat + ;; Bibliography Heading + (format "\n%s" "Bibliography_20_Heading" "References") + ;; Format Bibliography entries as a numbered list. + (format + "%s" + (mapconcat + (lambda (cite-key) + ;; Format each entry as a numbered item. + (format "\n%s\n" + (org-jabref-export-cite-key bib-file cite-key export-format))) + cite-keys "\n")))))) + +;;;; Bibliography :: Plain, Filtered + +;;;###autoload +(defun org-jabref-odt-bibliography/filtered (bibliography contents info) + "Transcode a BIBLIOGRAPHY element from Org to ODT. +CONTENTS is nil. INFO is a plist holding contextual information. + +Filter the BIB-FILE to just the cited entries. Export the +filtered BIB-FILE through `:bibliography' EXPORT-FORMAT, return +the result as string." + (let* ((bib-file (org-jabref--read-bibliography-attribute info :bib-file)) + ;; Reverse the entries in `:citation-alist' so that CITE-KEYs + ;; are sorted based on their order of occurrence in the Org + ;; file. + (cite-keys (mapcar 'car (plist-get info :citations-alist))) + (export-format (org-jabref--get-export-format info :bibliography))) + (message "Compiling BIBLIOGRAPHY (FILTERED)...") + (format "\n%s\n" + "OrgIndexSection" + "Bibliography" + (concat (format "\n%s" + "Bibliography_20_Heading" "References") + (org-jabref-export-bib-file-with-filtering + bib-file cite-keys export-format))))) + +;;;; Bibliography :: Plain, Unfiltered + +;;;###autoload +(defun org-jabref-odt-bibliography/unfiltered (bibliography contents info) + "Transcode a BIBLIOGRAPHY element from Org to ODT. +CONTENTS is nil. INFO is a plist holding contextual information. + +Export the BIB-FILE through `:bibliography' EXPORT-FORMAT, return +the result as string." + (let* ((bib-file (org-jabref--read-bibliography-attribute info :bib-file)) + (export-format (org-jabref--get-export-format info :bibliography))) + (message "Compiling BIBLIOGRAPHY UN-FILTERED" ) + (format "\n%s\n" + "OrgIndexSection" + "Bibliography" + (concat (format "\n%s" + "Bibliography_20_Heading" "References") + (org-jabref-export-bib-file bib-file export-format))))) + +;;;; Citation reference + +(defun org-jabref-odt-citation-reference (citation-reference contents info) + "Transcode a CITATION-REFERENCE element from Org to ODT. +CONTENTS is nil. INFO is a plist holding contextual information." + (let ((transcoder (car org-jabref-odt-citation-transcoders))) + (when (and transcoder (fboundp transcoder)) + (funcall transcoder citation-reference contents info)))) + + +;;;; Citation reference :: Plain Text (Author-Date etc.) + +;;;###autoload +(defun org-jabref-odt-citation-reference/text (citation-reference contents info) + "Transcode a CITATION-REFERENCE element from Org to ODT. +CONTENTS is nil. INFO is a plist holding contextual information. + +Pass each CITE-KEY from CITATION-REFERENCE in to `:in-text' +EXPORT-FORMAT. Return the concatenated result, after adding some +separators." + (let* ((latex-frag (org-element-property :value citation-reference)) + (value (and (string-match "\\\\cite{\\(.*?\\)}" latex-frag) + (match-string 1 latex-frag))) + (cite-keys (org-split-string value ",")) + (bib-file (org-jabref--read-bibliography-attribute info :bib-file)) + (export-format (org-jabref--get-export-format info :in-text))) + (mapconcat + (lambda (cite-key) + (message "Generating IN-TEXT entry for cite-key (%s)..." cite-key) + (org-jabref-export-cite-key bib-file cite-key export-format)) + cite-keys ", "))) + +(provide 'ox-jabref) + +;;; ox-jabref.el ends here diff --git a/etc/styles/OrgOdtStyles.xml b/etc/styles/OrgOdtStyles.xml index 3f408e2..5b1e973 100644 --- a/etc/styles/OrgOdtStyles.xml +++ b/etc/styles/OrgOdtStyles.xml @@ -776,6 +776,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lisp/org.el b/lisp/org.el index 8e970a1..56917ce 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -390,6 +390,7 @@ (defcustom org-modules '(org-w3m org-bbdb org-bibtex org-docview org-gnus org-in (const :tag " info: Links to Info nodes" org-info) (const :tag " inlinetask: Tasks independent of outline hierarchy" org-inlinetask) (const :tag " irc: Links to IRC/ERC chat sessions" org-irc) + (const :tag " JabRef: Export citations with JabRef" ox-jabref) (const :tag " mhe: Links to MHE folders/messages" org-mhe) (const :tag " mouse: Additional mouse support" org-mouse) (const :tag " protocol: Intercept calls from emacsclient" org-protocol) diff --git a/lisp/ox-odt.el b/lisp/ox-odt.el index 989d8e0..8de60db 100644 --- a/lisp/ox-odt.el +++ b/lisp/ox-odt.el @@ -82,10 +82,13 @@ (org-export-define-backend 'odt (timestamp . org-odt-timestamp) (underline . org-odt-underline) (verbatim . org-odt-verbatim) - (verse-block . org-odt-verse-block)) + (verse-block . org-odt-verse-block) + ;; Non-standard transcoders used just by the ODT exporter. + (citation-reference . org-odt-citation-reference)) :export-block "ODT" :filters-alist '((:filter-parse-tree - . (org-odt--translate-latex-fragments + . (org-odt--translate-cite-fragments + org-odt--translate-latex-fragments org-odt--translate-description-lists ; Dummy symbol org-odt--translate-list-tables))) :menu-entry @@ -1780,6 +1783,39 @@ (defun org-odt-footnote-reference (footnote-reference contents info) (funcall --format-footnote-definition n def)))))))) +;;;; Citation Reference + +(defun org-odt-citation-reference (citation-reference contents info) + "Transcode a CITATION-REFERENCE element from Org to ODT. +CONTENTS is nil. INFO is a plist holding contextual information." + ;; Citation references are treated like any other latex fragments. + ;; Citation processors (see ox-jabref.el) may handle citation + ;; references by registering their own transcoders. + (let ((latex-fragment citation-reference)) + (org-odt-latex-fragment latex-fragment contents info))) + +(defun org-odt-citation-reference/numbered (citation-reference contents info) + "Transcode a CITATION-REFERENCE element from Org to ODT. +CONTENTS is nil. INFO is a plist holding contextual information. + +Replace each CITE-KEY from CITATION-REFERENCE with it's numerical +order in the exported Org file. Return the concatenated result, +after adding some separators." + (let* ((latex-frag (org-element-property :value citation-reference)) + (value (and (string-match "\\\\cite{\\(.*?\\)}" latex-frag) + (match-string 1 latex-frag))) + (cite-keys (org-split-string value ","))) + (format "[%s]" + (mapconcat + (lambda (cite-key) + (let* ((citations-alist (plist-get info :citations-alist)) + (cite-key-entry (assoc cite-key citations-alist)) + (n (length (memq cite-key-entry citations-alist)))) + (format "%s" + cite-key (format "%d" n)))) + cite-keys ", ")))) + + ;;;; Headline (defun* org-odt-format-headline @@ -2045,6 +2081,11 @@ (defun org-odt-keyword (keyword contents info) ((member value '("tables" "figures" "listings")) ;; FIXME (ignore))))) + ;; Handle BIBLIOGRAPHY. Ignore it. + ((string= key "BIBLIOGRAPHY") + ;; Citation Processors (see ox-jabref.el) may handle this by + ;; registering their own transcoders. + (ignore)) ((string= key "PAGEBREAK") ;; Pagebreaks created this way are a mere expedience. These @@ -2109,8 +2150,7 @@ (defun org-odt-latex-environment (latex-environment contents info) (defun org-odt-latex-fragment (latex-fragment contents info) "Transcode a LATEX-FRAGMENT object from Org to ODT. CONTENTS is nil. INFO is a plist holding contextual information." - (let* ((latex-frag (org-element-property :value latex-fragment)) - (processing-type (plist-get info :with-latex))) + (let* ((latex-frag (org-element-property :value latex-fragment))) (format "%s" "OrgCode" (org-odt--encode-plain-text latex-frag t)))) @@ -3907,6 +3947,43 @@ (defun org-odt-verse-block (verse-block contents info) ;;; Filters +(defun org-odt--translate-cite-fragments (tree backend info) + "Translate all \\cite{} LaTeX fragments in TREE to `citation-reference'. +Return the translated tree. + +`citation-reference' is a non-standard element (stricly speaking, +an object) used internally by the ODT exporter. See +`org-odt-citation-transcoders'. + +Modify INFO plist by appending a `:citations-alist' property. +The value of this property is a list where each element is of the +form (CITE-KEY . CITATION-REFERENCE), with CITATION-REFERENCE +being the first element that references CITE-KEY. The list is +sorted in reverse order of appearance of CITE-KEYs in the +exported file." + (let ((citations-alist nil)) + (org-element-map tree 'latex-fragment + (lambda (latex-*) + (let* ((latex-frag (org-element-property :value latex-*))) + (when (string-match "\\\\cite{\\(.*?\\)}" latex-frag) + ;; LaTeX fragment matches \cite{...} + (let* ((value (match-string 1 latex-frag))) + ;; Replace LaTeX fragment with a `citation-reference' object. + (let* ((citation-reference (org-element-adopt-elements + (list 'citation-reference + (list :value latex-frag))))) + (org-element-set-element latex-* citation-reference) + ;; Check if this citation-reference is the first + ;; reference for any of the cite keys. + (let ((cite-keys (split-string value ","))) + (mapc (lambda (cite-key) + (unless (assoc cite-key citations-alist) + (push (cons cite-key latex-*) citations-alist))) + cite-keys))))))) info) + ;; Modify INFO by side-effects. + (nconc info (list :citations-alist citations-alist))) + tree) + ;;;; LaTeX fragments (defun org-odt--translate-latex-fragments (tree backend info) @@ -4242,6 +4319,7 @@ (defun org-odt--translate-list-tables (tree backend info) info) tree) + ;;; Interactive functions @@ -4375,7 +4453,7 @@ (defmacro org-odt--export-wrap (out-file &rest body) ;; Case 2: No further conversion. Return exported ;; OpenDocument file. (t target)))) - (error + ((debug error) ;; Cleanup work directory and work files. (funcall --cleanup-xml-buffers) (message "OpenDocument export failed: %s" -- 1.7.2.5