Files
emacs/lisp/org-ref/org-ref-export.el
2025-11-25 19:52:03 +01:00

888 lines
32 KiB
EmacsLisp

;;; org-ref-export.el --- org-ref-export library -*- lexical-binding: t; -*-
;;
;; Copyright (C) 2024 John Kitchin
;; Author: John Kitchin <jkitchin@andrew.cmu.edu>
;; Keywords: convenience
;; 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 3 of the License, 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. If not, see <http://www.gnu.org/licenses/>.
;;
;;; Commentary:
;; This is an export library that uses CSL to process the citations and bibliography.
;;
;; It is intended for non-LaTeX exports, but you can also use it with LaTeX if
;; you want to avoid using bibtex/biblatex for some reason.
;;
;; The default style is set by a CSL-STYLE keyword or
;; `org-ref-csl-default-style'. If this is an absolute or relative path that
;; exists, it is used. Otherwise, it looks in `org-cite-csl-styles-dir' from
;; `org-cite' if it is defined, and in the citeproc/csl-styles directory in
;; `org-ref' otherwise.
;;
;; The default locale is set by a CSL-LOCALE keyword or
;; `org-ref-csl-default-locale'. This is looked for in
;; `org-cite-csl-locales-dir' if it is defined, and otherwise in the csl-locales
;; directory of `org-ref'.
;;
;; Note that citeproc does not do anything for cross-references, so if non-LaTeX
;; export is your goal, you may want to use org-ref-refproc.el to handle
;; cross-references.
;;
;;; Formatting Limitations:
;;
;; Different export backends have different formatting capabilities. HTML and
;; LaTeX support full CSL formatting including small caps, italics, bold, etc.
;;
;; The org-mode backend has limitations because org-mode syntax does not support
;; small caps. Many CSL citation styles use small caps for author names, so these
;; will not render correctly when exporting to formats that use the org backend
;; (like DOCX by default).
;;
;; For DOCX export with better formatting support, set
;; `org-ref-docx-use-html-backend' to t. This causes citations to be rendered
;; as HTML which pandoc can convert to DOCX while preserving formatting.
;;
;; See `org-ref-backend-csl-formats' to customize backend mappings for different
;; export formats.
;;
;;; Code:
(require 'transient)
(require 'org-ref-utils)
(require 'org-ref-citation-links)
(defvar hfy-user-sheet-assoc) ; to quiet compiler
(require 'ox-org)
(when (executable-find "pandoc")
(ignore-errors (require 'ox-pandoc)))
(ignore-errors (require 'citeproc))
(defvar org-cite-csl-styles-dir)
(defcustom org-ref-backend-csl-formats
'((html . html)
(latex . latex)
(md . plain)
(org . org)
(ascii . plain)
(odt . org-odt)
(docx . org))
"Mapping of export backend to csl-backends.
Each entry maps an org export backend symbol to a citeproc-el backend
format used for rendering citations and bibliographies.
Note: The 'org backend has formatting limitations because org-mode
syntax does not support small caps. CSL styles that use small caps
(common for author names) will not render correctly when using the
'org backend. For DOCX export, consider setting
`org-ref-docx-use-html-backend' to t to use HTML formatting which
pandoc can convert while preserving small caps and other formatting.
Available citeproc backends:
- html: Full HTML formatting with CSS styles
- latex: Full LaTeX formatting with commands like \\textsc{}
- org: Org-mode markup (limited, no small caps support)
- org-odt: ODT-specific XML formatting
- plain: Plain text with no formatting"
:type '(alist :key-type (symbol) :value-type (symbol))
:group 'org-ref)
(defcustom org-ref-cite-internal-links 'auto
"Should be one of these symbols (quoted)
- bib-links :: link cites to bibliography entries
- no-links :: do not link cites to bibliography entries
- nil or auto :: add links based on the style."
:type '(choice symbol (sexp :tag bib-links)
symbol (sexp :tag no-links)
symbol (sexp :tag auto-links)
symbol (sexp :tag nil))
:group 'org-ref)
(defcustom org-ref-csl-default-style "chicago-author-date-16th-edition.csl"
"Default csl style to use.
Should be a csl filename, or an absolute path to a csl filename."
:type 'string
:group 'org-ref)
(defcustom org-ref-csl-default-locale "en-US"
"Default csl locale to use."
:type 'string
:group 'org-ref)
(defcustom org-ref-docx-use-html-backend nil
"Use HTML backend for DOCX export to preserve CSL formatting.
When non-nil, citations exported to DOCX will be rendered using the
HTML backend, which preserves formatting like small caps and italics
that pandoc can convert to DOCX.
When nil (default), uses the org backend which has limited formatting
support due to org-mode syntax limitations. Specifically, org-mode has
no native syntax for small caps, so CSL styles that use small caps
(common for author names in many citation styles) will not render
correctly in DOCX output.
Note: This option only affects DOCX export via pandoc. Other export
formats (HTML, LaTeX, ODT) are not affected.
See also `org-ref-backend-csl-formats' to customize backend mappings
for other export formats.
Related to issue #981: https://github.com/jkitchin/org-ref/issues/981"
:type 'boolean
:group 'org-ref)
(defcustom org-ref-csl-label-aliases
'((("app" "apps") . "appendix")
(("art" "arts") . "article-locator")
(("bk" "bks") . "book")
(("can") . "canon")
(("ch" "chap" "chaps" "chapt") . "chapter")
(("col" "cols") . "column")
(("el") . "elocation")
(("eq" "eqs") . "equation")
(("fig" "figs") . "figure")
(("fol" "fols") . "folio")
(("iss") . "issue")
(("l" "ll") . "line")
(("n" "nn") . "note")
;; number is not listed in the url in the docstring
(("no" "nos" "#") . "number")
(("op" "opp") . "opus")
(("p" "pp" "pg" "pgs") . "page")
(("para" "paras" "" "¶¶" "§" "§§") . "paragraph")
(("pt" "pts") . "part")
(("sec" "secs") . "section")
(("s.v" "s.vv") . "sub verbo")
(("sup" "supp") . "supplement")
(("tab" "tabs") . "table")
(("ts") . "timestamp")
(("ti" "tit") . "title")
(("v" "vv") . "verse")
(("vol" "vols") . "volume"))
"A-list of aliases for a csl label.
The car is a list of possible aliases (including if they end in a .
This list was adapted from `org-cite-csl--label-alist'.
See https://github.com/citation-style-language/documentation/blob/master/specification.rst#locators"
:type '(alist :key-type (list (repeat string)) :value-type string)
:group 'org-ref)
(defcustom org-ref-export-suppress-affix-types
'("citet"
"citet*"
"citetitle"
"citeyear"
"citeauthor"
"citenum"
"textcite")
"List of cite types to suppress affixes (usually parentheses) on."
:type '(list (repeat string))
:group 'org-ref)
;;; Footnote citation support (issue #993)
(defvar org-ref-footnote-counter 0
"Counter for footnote citations during export.
Reset to 0 at the start of each export process.")
(defcustom org-ref-footnote-cite-types
'("footcite"
"footfullcite"
"footcitetext"
"footcites"
"footcitetexts"
"smartcite"
"Smartcite")
"List of citation types that should be rendered as footnotes.
These citation types will be given a :note-index parameter when
passed to citeproc-el, which causes them to be rendered as notes/footnotes
when using CSL styles that support note formatting."
:type '(repeat string)
:group 'org-ref)
(defun org-ref-footnote-cite-type-p (cite-type)
"Return non-nil if CITE-TYPE should be rendered as a footnote.
CITE-TYPE is a string like \"footcite\" or \"cite\"."
(member cite-type org-ref-footnote-cite-types))
(defun org-ref-get-next-footnote-number ()
"Get the next footnote number and increment the counter.
Returns the next sequential footnote number (1, 2, 3, ...)."
(setq org-ref-footnote-counter (1+ org-ref-footnote-counter)))
(defun org-ref-csl-style-supports-notes-p (csl-style-file)
"Return non-nil if CSL-STYLE-FILE supports note/footnote formatting.
CSL-STYLE-FILE is a filename like \"chicago-fullnote-bibliography.csl\".
This function checks if the CSL style file contains note-related
class attributes, which indicate it supports footnote formatting."
(or
;; Check filename for common note-style indicators
;; Match: -note-, -note.csl, fullnote, footnote
(string-match-p "\\(\\bnote\\b\\|fullnote\\|footnote\\)" csl-style-file)
;; If we have the actual file, check its contents
(when (file-exists-p csl-style-file)
(with-temp-buffer
(insert-file-contents csl-style-file)
(goto-char (point-min))
;; Look for class="note" in the CSL XML
(re-search-forward "class=\"note\"" nil t)))))
(defun org-ref-get-citation-note-index (citation-link)
"Get the note-index for CITATION-LINK if it's a footnote citation type.
CITATION-LINK is an org-element link object.
Returns a footnote number if this is a footnote citation, nil otherwise."
(when (org-ref-footnote-cite-type-p
(org-element-property :type citation-link))
(org-ref-get-next-footnote-number)))
(defun org-ref-dealias-label (alias)
"Return the full, de-aliased label for ALIAS.
Looked up from `org-ref-csl-label-aliases'.
I added this because I think it is reasonable to expect if you
write pg. 2 that it will show that way when rendered. At the
moment that is not the case, and only page is accepted. This is
actually done in oc-csl too, although it uses a flat a-list."
(or (cdr (assoc "page" org-ref-csl-label-aliases
(lambda (x1 _x2)
(or (member alias x1)
(member (concat (downcase alias) ".") x1)))))
alias))
(defun org-ref-get-cite-links ()
"Return list of cite links in the order they appear in the buffer."
(org-element-map (org-element-parse-buffer) 'link
(lambda (lnk)
(when (assoc (org-element-property :type lnk) org-ref-cite-types)
lnk))))
(defun org-ref-ref-csl-data (ref type)
"Return the CSL alist for a REF of TYPE.
REF is a plist data structure returned from `org-ref-parse-cite-path'."
;; I believe the suffix contains "label locator suffix"
;; where locator is a number, or maybe a range of numbers like 5-6.
;; label is something like page or chapter
;; and the rest is the suffix text.
;; For example: ch. 5, for example
;; would be label = ch., locator=5, ",for example" as suffix.
(let* ((full-suffix (string-trim (or (plist-get ref :suffix) "")))
locator
label locator suffix)
;; org-cite is more sophisticated than this and would allow things like 5, 6
;; and 12. I am not sure about what all should be supported yet. I guess the
;; idea there is you use everything from the first to last number as the
;; locator, but that seems tricky, what about something like: 5, 6 and 12,
;; because he had 3 books. One solution might be some kind of delimiter,
;; e.g. {5, 6 and 12}, because he had 3 books.
(if (and (string-match
(rx-to-string
`(seq
;; optional label
(group-n 1 (optional
(regexp ,(regexp-opt (cl-loop for (abbrvs . full)
in org-ref-csl-label-aliases
append (append abbrvs (list full)))))))
(optional (one-or-more space))
;; number or numeric ranges
(group-n 2 (one-or-more digit) (optional "-" (one-or-more digit)))
;; everything else
(group-n 3 (* "."))))
full-suffix)
(match-string 2 full-suffix)
(not (string= "" (match-string 2 full-suffix))))
;; We found a locator
(setq label (match-string 1 full-suffix)
locator (match-string 2 full-suffix)
suffix (match-string 3 full-suffix))
(setq label nil
locator nil
suffix full-suffix))
;; Let's assume if you have a locator but not a label that you mean page.
(when (and locator (string= "" (string-trim label)))
(setq label "page"))
`((id . ,(plist-get ref :key))
(prefix . ,(plist-get ref :prefix))
(suffix . ,suffix)
(locator . ,locator)
(label . ,(when label (org-ref-dealias-label (string-trim label))))
;; [2024-01-29 Mon] see
;; https://github.com/jkitchin/org-ref/issues/1103#issuecomment-1915028374
;; and related comments at
;; https://github.com/andras-simonyi/citeproc-el/issues/151. It seems I
;; should not be adding this. TODO: proof of concept and not complete. I
;; did not go through all the types to see what else should be in here.
;; (suppress-author . ,(not (null (member type '("citenum" "citeyear"
;; "citeyear*" "citedate" "citedate*" "citetitle" "citetitle*"
;; "citeurl")))))
)))
(declare-function org-ref-find-bibliography "org-ref-core")
(defun org-ref-process-buffer (backend &optional subtreep)
"Process the citations and bibliography in the org-buffer.
Usually run on a copy of the buffer during export.
BACKEND is the org export backend."
;; Reset footnote counter for this export
(setq org-ref-footnote-counter 0)
(save-restriction
(when subtreep
(org-narrow-to-subtree))
(let* ((csl-backend (or (cdr (assoc backend org-ref-backend-csl-formats)) 'plain))
;; Use HTML backend for DOCX if requested for better formatting
(csl-backend (if (and (eq backend 'docx) org-ref-docx-use-html-backend)
'html
csl-backend))
(style (or (cadr (assoc "CSL-STYLE"
(org-collect-keywords
'("CSL-STYLE"))))
org-ref-csl-default-style))
(locale (or (cadr (assoc "CSL-LOCALE"
(org-collect-keywords
'("CSL-LOCALE"))))
org-ref-csl-default-locale))
;; Determine the actual style file path for checking note support
(style-file (cond
((file-exists-p style)
style)
((and (bound-and-true-p org-cite-csl-styles-dir)
(file-exists-p (org-ref--file-join org-cite-csl-styles-dir style)))
(org-ref--file-join org-cite-csl-styles-dir style))
((file-exists-p (expand-file-name style
(org-ref--file-join (file-name-directory
(locate-library "org-ref"))
"citeproc/csl-styles")))
(expand-file-name style (org-ref--file-join
(file-name-directory
(locate-library "org-ref"))
"citeproc/csl-styles")))
(t
style))) ; Fallback to style name itself
(proc (citeproc-create
;; The style
(cond
((file-exists-p style)
style)
;; In a user-dir
((and (bound-and-true-p org-cite-csl-styles-dir)
(file-exists-p (org-ref--file-join org-cite-csl-styles-dir style)))
(org-ref--file-join org-cite-csl-styles-dir style))
;; provided by org-ref
((file-exists-p (expand-file-name style
(org-ref--file-join (file-name-directory
(locate-library "org-ref"))
"citeproc/csl-styles")))
(expand-file-name style (org-ref--file-join
(file-name-directory
(locate-library "org-ref"))
"citeproc/csl-styles")))
(t
(error "%s not found" style)))
;; item-getter
;; (citeproc-itemgetter-from-bibtex (org-ref-find-bibliography))
(citeproc-hash-itemgetter-from-any (org-ref-find-bibliography) t)
;; locale getter
(citeproc-locale-getter-from-dir (if (bound-and-true-p org-cite-csl-locales-dir)
org-cite-csl-locales-dir
(org-ref--file-join (file-name-directory
(locate-library "org-ref"))
"citeproc/csl-locales")))
;; the actual locale
locale))
;; list of links in the buffer
(cite-links (org-element-map (org-element-parse-buffer) 'link
(lambda (lnk)
(when (assoc (org-element-property :type lnk) org-ref-cite-types)
lnk))))
(cites (cl-loop for cl in cite-links collect
(let* ((cite-data (org-ref-parse-cite-path (org-element-property :path cl)))
(common-prefix (or (plist-get cite-data :prefix) ""))
(common-suffix (or (plist-get cite-data :suffix) ""))
(refs (plist-get cite-data :references))
(type (org-element-property :type cl))
(cites (cl-loop for ref in refs collect
(org-ref-ref-csl-data ref type))))
;; TODO: update eventually
;; https://github.com/andras-simonyi/citeproc-el/issues/46
;; To handle common prefixes, suffixes, I just concat
;; them with the first/last entries. That is all that
;; is supported for now. Combine common/local prefix
(setf (cdr (assoc 'prefix (cl-first cites)))
(concat common-prefix
(cdr (assoc 'prefix (cl-first cites)))))
;; Combine local/common suffix
(setf (cdr (assoc 'suffix (car (last cites))))
(concat (cdr (assoc 'suffix (car (last cites))))
common-suffix))
;; https://github.com/andras-simonyi/citeproc-el#creating-citation-structures
(citeproc-citation-create
:cites cites
:suppress-affixes (let ((type (org-element-property :type cl)))
(when (member type
org-ref-export-suppress-affix-types)
t))
;; TODO: this is proof of concept, and not complete.
;; mode is one of suppress-author, textual,
;; author-only, year-only, or nil for default. These
;; are not all clear to me.
:mode (let ((type (org-element-property :type cl)))
(cond
((member type '("citet" "citet*"))
'textual)
((member type '("citeauthor" "citeauthor*"))
'author-only)
((member type '("citeyear" "citeyear*"))
'year-only)
((member type '("citedate" "citedate*"))
'suppress-author)
(t
nil)))
;; I think the capitalized styles are what this is for
:capitalize-first (string-match
"[A-Z]"
(substring
(org-element-property :type cl) 0 1))
;; Set note-index for footnote citation types (issue #993)
:note-index (when (org-ref-footnote-cite-type-p
(org-element-property :type cl))
;; Warn if using footnote citations with non-note style
(unless (org-ref-csl-style-supports-notes-p style-file)
(warn "Citation type '%s' is a footnote citation but CSL style '%s' may not support notes. Consider using a note-based style like chicago-fullnote-bibliography.csl"
(org-element-property :type cl)
style))
(org-ref-get-next-footnote-number))
:ignore-et-al nil
:grouped nil))))
(rendered-citations (progn (citeproc-append-citations cites proc)
(citeproc-render-citations proc csl-backend org-ref-cite-internal-links)))
;; I only use the returned bibliography string. citeproc returns a
;; bunch of other things related to offsets and linespacing, but I
;; don't know what you do with these, so just ignore them here.
(bibdata (citeproc-render-bib proc csl-backend))
(rendered-bib (car bibdata))
(bib-parameters (cdr bibdata))
;; The idea is we will wrap each citation and the bibliography in
;; org-code so it exports appropriately.
(cite-formatters '((html . "@@html:%s@@")
(latex . "@@latex:%s@@")
(odt . "@@odt:%s@@")))
(bib-formatters '((html . "\n#+BEGIN_EXPORT html\n%s\n#+END_EXPORT\n")
(latex . "\n#+BEGIN_EXPORT latex\n%s\n#+END_EXPORT\n")
(odt . "\n#+BEGIN_EXPORT ODT\n%s\n#+END_EXPORT\n"))))
;; replace the cite links
(cl-loop for cl in (reverse cite-links) for rc in (reverse rendered-citations) do
(cl--set-buffer-substring (org-element-property :begin cl)
(org-element-property :end cl)
(format (or
(cdr (assoc backend cite-formatters))
"%s")
(concat
rc
;; Add on extra spaces that were
;; following it.
(make-string
(or
(org-element-property :post-blank cl) 0)
? )))))
;; Decorate the bibliography for different outputs adapted from
;; `org-cite-csl-render-bibliography' in oc-csl I don't know what all
;; these do or how to use them in the CSS for html, or LaTeX. This is to
;; fix an annoying HTML feature that has an extra line in the numbering.
;; This seems to do the right thing. I don't support hanging-indent like
;; oc-csl does, and I don't currently support LaTeX here. It already does
;; a good job there.
;;
;; (find-library "oc-csl")
;;
;; Here are some examples of what is in the bib-parameters.
;; (max-offset . 2) (hanging-indent) (second-field-align . flush)
;; (entry-spacing . 0)
;; (line-spacing . 2)
;;
;; Here we add style css for html output.
(cond
((or (eq 'html backend) (eq 'html csl-backend))
(let ((s1 "")
(s2 ""))
(when (cdr (assq 'second-field-align bib-parameters))
(setq s1 (format
"<style>.csl-left-margin{float: left; padding-right: 0em;}
.csl-right-inline{margin: 0 0 0 %dem;}</style>"
;; I hard coded this factor of 0.6 from the oc-csl code.
(* 0.6 (or (cdr (assq 'max-offset bib-parameters)) 0)))))
;; hard-coded the hanging indent. oc-csl uses a variable for this. I
;; guess we could too, but this seems simpler.
(when (cdr (assq 'hanging-indent bib-parameters))
(setq s2 "<style>.csl-entry{text-indent: -1.5em; margin-left: 1.5em;}</style>"))
(setq rendered-bib (concat
s1 s2
rendered-bib)))))
;; replace the bibliography
(org-element-map (org-element-parse-buffer) 'link
(lambda (lnk)
(cond
((string= (org-element-property :type lnk) "bibliography")
(cl--set-buffer-substring (org-element-property :begin lnk)
(org-element-property :end lnk)
(format (or
(cdr (assoc backend bib-formatters))
"%s")
rendered-bib)))
;; We just get rid of nobibliography links.
((string= (org-element-property :type lnk) "nobibliography")
(cl--set-buffer-substring (org-element-property :begin lnk)
(org-element-property :end lnk)
"")))))
;; For LaTeX we need to define the citeprocitem commands
;; see https://www.mail-archive.com/emacs-orgmode@gnu.org/msg138546.html
(when (eq backend 'latex)
(goto-char (point-min))
(insert "#+latex_header: \\makeatletter
#+latex_header: \\newcommand{\\citeprocitem}[2]{\\hyper@linkstart{cite}{citeproc_bib_item_#1}#2\\hyper@linkend}
#+latex_header: \\makeatother\n")))))
(defun org-ref-export-to (backend &optional async subtreep visible-only
body-only info)
"Export buffer to BACKEND.
See `org-export-as' for the meaning of ASYNC SUBTREEP
VISIBLE-ONLY BODY-ONLY and INFO."
(let* ((fname (buffer-file-name))
(extensions '((html . ".html")
(latex . ".tex")
(ascii . ".txt")
(md . ".md")
(odt . ".odf")))
(cp (point))
(mm) ;marker to save place
(export-name (concat (file-name-sans-extension fname)
(or (cdr (assoc backend extensions)) ""))))
(org-export-with-buffer-copy
;; Note I use a marker here to make sure we stay in the same place we were.
;; This is more robust than save-excursion I think, since processing moves
;; points around. In theory the marker should move too.
(setq mm (make-marker))
(move-marker mm cp)
;; make sure we expand includes
(org-export-expand-include-keyword)
(goto-char (marker-position mm))
(org-ref-process-buffer backend subtreep)
(set-marker mm nil)
(pcase backend
;; odt is a little bit special, and is missing one argument
('odt (org-open-file (org-odt-export-to-odt async subtreep visible-only
info)
'system))
;; for pandoc, we mean make a docx via pandoc
('docx (org-open-file (plist-get (org-pandoc-export-to-docx async subtreep visible-only
body-only info)
'output-file)
'system))
(_
(org-open-file (org-export-to-file backend export-name
async subtreep visible-only
body-only info)
'system))))))
;; I guess I tried to use apply-partially here, and it did not work, so these
;; are each defined manually
(defun org-ref-export-to-html (&optional async subtreep visible-only
body-only info)
"Export the buffer to HTML and open.
See `org-export-as' for the meaning of ASYNC SUBTREEP
VISIBLE-ONLY BODY-ONLY and INFO."
(org-ref-export-to 'html async subtreep visible-only
body-only info))
(defun org-ref-export-to-ascii (&optional async subtreep visible-only
body-only info)
"Export the buffer to ascii and open.
See `org-export-as' for the meaning of ASYNC SUBTREEP
VISIBLE-ONLY BODY-ONLY and INFO."
(org-ref-export-to 'ascii async subtreep visible-only
body-only info))
(defun org-ref-export-to-md (&optional async subtreep visible-only
body-only info)
"Export the buffer to md and open.
See `org-export-as' for the meaning of ASYNC SUBTREEP
VISIBLE-ONLY BODY-ONLY and INFO."
(org-ref-export-to 'md async subtreep visible-only
body-only info))
(defun org-ref-export-to-pdf (&optional async subtreep visible-only
body-only info)
"Export the buffer to PDF via LaTeX and open.
See `org-export-as' for the meaning of ASYNC SUBTREEP
VISIBLE-ONLY BODY-ONLY and INFO."
(let ((org-export-before-parsing-functions (append
org-export-before-parsing-functions
'(org-ref-csl-preprocess-buffer))))
(org-open-file (org-latex-export-to-pdf async subtreep visible-only
body-only info))))
(defun org-ref-export-to-latex (&optional async subtreep visible-only
body-only info)
"Export the buffer to LaTeX and open.
See `org-export-as' for the meaning of ASYNC SUBTREEP
VISIBLE-ONLY BODY-ONLY and INFO."
(org-ref-export-to 'latex async subtreep visible-only
body-only info))
(defun org-ref-export-to-odt (&optional async subtreep visible-only
body-only info)
"Export the buffer to ODT and open.
See `org-export-as' for the meaning of ASYNC SUBTREEP
VISIBLE-ONLY BODY-ONLY and INFO."
(require 'htmlfontify)
(unless (boundp 'hfy-user-sheet-assoc) (setq hfy-user-sheet-assoc nil))
(org-ref-export-to 'odt async subtreep visible-only
body-only info))
(defun org-ref-export-to-docx (&optional async subtreep visible-only
body-only info)
"Export the buffer to docx via pandoc and open.
Note: By default, DOCX export uses the org backend for citations which
has formatting limitations (no small caps support). Set
`org-ref-docx-use-html-backend' to t for better formatting preservation.
See `org-export-as' for the meaning of ASYNC SUBTREEP
VISIBLE-ONLY BODY-ONLY and INFO."
(org-ref-export-to 'docx async subtreep visible-only
body-only info))
(defun org-ref-export-as-org (&optional _async subtreep visible-only
body-only info)
"Export the buffer to an ORG buffer and open.
We only make a buffer here to avoid overwriting the original file.
See `org-export-as' for the meaning of ASYNC SUBTREEP
VISIBLE-ONLY BODY-ONLY and INFO."
(let* ((export-buf "*org-ref ORG Export*")
export)
(org-export-with-buffer-copy
(org-ref-process-buffer 'org subtreep)
(setq export (org-export-as 'org subtreep visible-only body-only info))
(with-current-buffer (get-buffer-create export-buf)
(erase-buffer)
(org-mode)
(insert export)))
(pop-to-buffer export-buf)))
(defun org-ref-export-to-message (&optional _async subtreep visible-only
body-only info)
"Export to ascii and insert in an email message."
(let* ((backend 'ascii)
(content (org-export-with-buffer-copy
(org-ref-process-buffer backend subtreep)
(org-export-as backend subtreep visible-only
body-only info))))
(compose-mail)
(message-goto-body)
(insert content)
(message-goto-to)))
(org-export-define-derived-backend 'org-ref 'org
:menu-entry
'(?r "Org-ref export"
((?a "to Ascii" org-ref-export-to-ascii)
(?m "to markdown" org-ref-export-to-md)
(?h "to html" org-ref-export-to-html)
(?l "to LaTeX" org-ref-export-to-latex)
(?p "to PDF" org-ref-export-to-pdf)
(?o "to ODT" org-ref-export-to-odt)
(?O "to Org buffer" org-ref-export-as-org)
(?e "to email" org-ref-export-to-message)
(?w "to docx" org-ref-export-to-docx))))
;; An alternative to this exporter is to use an `org-export-before-parsing-functions'
;; (add-hook 'org-export-before-parsing-functions 'org-ref-csl-preprocess-buffer)
(defun org-ref-csl-preprocess-buffer (backend)
"Preprocess the buffer in BACKEND export.
Note this may not work as expected, what about subtreep? The hook
function just takes one argument. For now we rely on
`buffer-narrowed-p' and an org-heading at the beginning.
I am not positive on this though."
(org-ref-process-buffer backend (and (buffer-narrowed-p)
(save-excursion
(goto-char (point-min))
(org-at-heading-p)))))
;; A transient exporter with preprocessors
(defvar org-ref/natmove nil
"Toggle for moving natbib citations before export.")
(defvar org-ref/citeproc nil
"Toggle for running citeproc before export.")
(defvar org-ref/refproc nil
"Toggle for running refproc before export.")
(defvar org-ref/acrossproc nil
"Toggle for running acrossproc before export.")
(defvar org-ref/idxproc nil
"Toggle for running idxproc before export.")
(defvar org-ref/bblproc nil
"Toggle for running bblproc before export.")
(defun org-ref-export--toggle (var)
(set var (not (symbol-value var)))
(message "%s %s"
(capitalize (replace-regexp-in-string "/" " " (symbol-name var)))
(if (symbol-value var) "enabled" "disabled"))
(symbol-value var))
(defun org-ref-export-toggle-natmove ()
(interactive)
(org-ref-export--toggle 'org-ref/natmove))
(defun org-ref-export-toggle-citeproc ()
(interactive)
(org-ref-export--toggle 'org-ref/citeproc))
(defun org-ref-export-toggle-refproc ()
(interactive)
(org-ref-export--toggle 'org-ref/refproc))
(defun org-ref-export-toggle-acrossproc ()
(interactive)
(org-ref-export--toggle 'org-ref/acrossproc))
(defun org-ref-export-toggle-idxproc ()
(interactive)
(org-ref-export--toggle 'org-ref/idxproc))
(defun org-ref-export-toggle-bblproc ()
(interactive)
(org-ref-export--toggle 'org-ref/bblproc))
(defun org-ref-export--toggle-description (label var)
(format "%s %s" label (if (symbol-value var) "[on]" "[off]")))
(defun org-ref-export-dispatch (&optional arg)
"Run the export dispatcher with the desired hooks selected in the export menu."
(interactive "P")
(when (and org-ref/citeproc org-ref/bblproc)
(error "You cannot use CSL and BBL at the same time."))
(let ((org-export-before-parsing-functions org-export-before-parsing-functions))
(when org-ref/citeproc
(cl-pushnew 'org-ref-csl-preprocess-buffer org-export-before-parsing-functions))
(when org-ref/refproc
(cl-pushnew 'org-ref-refproc org-export-before-parsing-functions))
(when org-ref/acrossproc
(cl-pushnew 'org-ref-acrossproc org-export-before-parsing-functions))
(when org-ref/idxproc
(cl-pushnew 'org-ref-idxproc org-export-before-parsing-functions))
(when org-ref/bblproc
(unless (featurep 'org-ref-natbib-bbl-citeproc)
(require 'org-ref-natbib-bbl-citeproc))
(cl-pushnew 'org-ref-bbl-preprocess org-export-before-parsing-functions))
;; this goes last since it moves cites before they might get replaced.
(when org-ref/natmove
(cl-pushnew 'org-ref-cite-natmove org-export-before-parsing-functions))
(org-export-dispatch arg)))
(transient-define-prefix org-ref-export-menu ()
"Select export preprocessors and dispatch export."
[["Preprocessors"
("n" org-ref-export-toggle-natmove :transient t
:description (lambda () (org-ref-export--toggle-description "natmove" 'org-ref/natmove)))
("c" org-ref-export-toggle-citeproc :transient t
:description (lambda () (org-ref-export--toggle-description "citeproc" 'org-ref/citeproc)))
("r" org-ref-export-toggle-refproc :transient t
:description (lambda () (org-ref-export--toggle-description "refproc" 'org-ref/refproc)))
("a" org-ref-export-toggle-acrossproc :transient t
:description (lambda () (org-ref-export--toggle-description "acrossproc" 'org-ref/acrossproc)))
("i" org-ref-export-toggle-idxproc :transient t
:description (lambda () (org-ref-export--toggle-description "idxproc" 'org-ref/idxproc)))
("b" org-ref-export-toggle-bblproc :transient t
:description (lambda () (org-ref-export--toggle-description "bblproc" 'org-ref/bblproc)))]
["Actions"
("e" "Export" org-ref-export-dispatch)
("q" "Quit" transient-quit-one)]])
(define-obsolete-function-alias 'org-ref-export/body
#'org-ref-export-menu "3.1")
(define-obsolete-function-alias 'org-ref-export-from-hydra
#'org-ref-export-dispatch "3.1")
(provide 'org-ref-export)
;;; org-ref-export.el ends here