branch: externals/org commit d6cb37f4be3edd5e4d4c5a2eca6097404c0bfce5 Author: Nicolas Goaziou <m...@nicolasgoaziou.fr> Commit: Nicolas Goaziou <m...@nicolasgoaziou.fr>
oc-natbib: Implement `natbib' citation processor * lisp/oc-natbib.el: New file. --- lisp/oc-natbib.el | 189 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 189 insertions(+) diff --git a/lisp/oc-natbib.el b/lisp/oc-natbib.el new file mode 100644 index 0000000..59951c5 --- /dev/null +++ b/lisp/oc-natbib.el @@ -0,0 +1,189 @@ +;;; oc-natbib.el --- Citation processor using natbib LaTeX package -*- lexical-binding: t; -*- + +;; Copyright (C) 2021 Free Software Foundation, Inc. + +;; Author: Nicolas Goaziou <m...@nicolasgoaziou.fr> + +;; 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 <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; This library registers the `natbib' citation processor, which provides the +;; "export" capability for citations. + +;; The processor relies on "natbib" LaTeX package. As such it ensures that the +;; package is properly required in the document's preamble. More accurately, it +;; will use any "\\usepackage{natbib}" command already present in the document +;; (e.g., through `org-latex-packages-alist'), or insert one using options +;; defined in `org-cite-natbib-options'. + +;; It supports the following citation styles: +;; +;; - author (a), including caps (c), and full (f) variants, +;; - noauthor (na), including bare (b) variant, +;; - text (t), including bare (b), caps (c), full (f), bare-caps (bc), +;; bare-full (bf), caps-full (cf), and bare-caps-full (bcf) variants, +;; - default, including bare (b), caps (c), full (f), bare-caps (bc), +;; bare-full (bf), caps-full (cf), and bare-caps-full (bcf) variants. + +;; Bibliography accepts any style supported by "natbib" package. + +;;; Code: +(require 'oc) + +(declare-function org-element-property "org-element" (property element)) + +(declare-function org-export-data "org-export" (data info)) + + +;;; Customization +(defcustom org-cite-natbib-options nil + "List of options added to \"natbib\" package. +If \"natbib\" package is already required in the document, e.g., through +`org-latex-packages-alist' variable, these options are ignored." + :group 'org-cite + :package-version '(Org . "9.5") + :type + '(set + (const :tag "use round parentheses (default)" round) + (const :tag "use square brackets" square) + (const :tag "use curly braces" curly) + (const :tag "use angle brackets" angle) + (const :tag "separate multiple citations with colons (default)" colon) + (const :tag "separate multiple citations with comas" comma) + (const :tag "generate author-year citations" authoryear) + (const :tag "generate numerical citations" numbers) + (const :tag "generate superscripted numerical citations" super) + (const :tag "order multiple citations according to the list of references" sort) + (const :tag "order as above, but numerical citations are compressed if possible" sort&compress) + (const :tag "display full author list on first citation, abbreviate the others" longnamesfirst) + (const :tag "redefine \\thebibliography to issue \\section* instead of \\chapter*" sectionbib) + (const :tag "keep all the authors' names in a citation on one line" nonamebreak)) + :safe t) + + +;;; Internal functions +(defun org-cite-natbib--style-to-command (style) + "Return command name to use according to STYLE pair." + (pcase style + ;; "author" style. + (`(,(or "author" "a") . ,(or "caps" "c")) "\\Citeauthor") + (`(,(or "author" "a") . ,(or "full" "f")) "\\citeauthor*") + (`(,(or "author" "a") . ,_) "\\citeauthor") + ;; "noauthor" style. + (`(,(or "noauthor" "na") . ,(or "bare" "b")) "\\citeyear") + (`(,(or "noauthor" "na") . ,_) "\\citeyearpar") + ;; "nocite" style. + (`(,(or "nocite" "n") . ,_) "\\nocite") + ;; "text" style. + (`(,(or "text" "t") . ,(or "bare" "b")) "\\citealt") + (`(,(or "text" "t") . ,(or "caps" "c")) "\\Citet") + (`(,(or "text" "t") . ,(or "full" "f")) "\\citet*") + (`(,(or "text" "t") . ,(or "bare-caps" "bc")) "\\Citealt") + (`(,(or "text" "t") . ,(or "bare-full" "bf")) "\\citealt*") + (`(,(or "text" "t") . ,(or "caps-full" "cf")) "\\Citet*") + (`(,(or "text" "t") . ,(or "bare-caps-full" "bcf")) "\\Citealt*") + (`(,(or "text" "t") . ,_) "\\citet") + ;; Default ("nil") style. + (`(,_ . ,(or "bare" "b")) "\\citealp") + (`(,_ . ,(or "caps" "c")) "\\Citep") + (`(,_ . ,(or "full" "f")) "\\citep*") + (`(,_ . ,(or "bare-caps" "bc")) "\\Citealp") + (`(,_ . ,(or "bare-full" "bf")) "\\citealp*") + (`(,_ . ,(or "caps-full" "cf")) "\\Citep*") + (`(,_ . ,(or "bare-caps-full" "bcf")) "\\Citealp*") + (`(,_ . ,_) "\\citep") + ;; This should not happen. + (_ (error "Invalid style: %S" style)))) + +(defun org-cite-natbib--build-optional-arguments (citation info) + "Build optional arguments for citation command. +CITATION is the citation object. INFO is the export state, as a property list." + (let* ((origin (pcase (org-cite-get-references citation) + (`(,reference) reference) + (_ citation))) + (suffix (org-element-property :suffix origin)) + (prefix (org-element-property :prefix origin))) + (concat (and prefix (format "[%s]" (org-trim (org-export-data prefix info)))) + (cond + (suffix (format "[%s]" (org-trim (org-export-data suffix info)))) + (prefix "[]") + (t nil))))) + +(defun org-cite-natbib--build-arguments (citation) + "Build arguments for citation command for CITATION object." + (format "{%s}" + (mapconcat #'identity + (org-cite-get-references citation t) + ","))) + + +;;; Export capability +(defun org-cite-natbib-export-bibliography (_keys files style &rest _) + "Print references from bibliography FILES. +FILES is a list of absolute file names. STYLE is the bibliography style, as +a string or nil." + (concat (and style (format "\\bibliographystyle{%s}\n" style)) + (format "\\bibliography{%s}" + (mapconcat #'file-name-sans-extension + files + ",")))) + +(defun org-cite-natbib-export-citation (citation style _ info) + "Export CITATION object. +STYLE is the citation style, as a pair of strings or nil. INFO is the export +state, as a property list." + (concat (org-cite-natbib--style-to-command style) + (org-cite-natbib--build-optional-arguments citation info) + (org-cite-natbib--build-arguments citation))) + +(defun org-cite-natbib-use-package (output &rest _) + "Ensure output requires \"natbib\" package. +OUTPUT is the final output of the export process." + (with-temp-buffer + (save-excursion (insert output)) + (when (search-forward "\\begin{document}" nil t) + ;; Ensure there is a \usepackage{natbib} somewhere or add one. + (goto-char (match-beginning 0)) + (let ((re (rx "\\usepackage" (opt "[" (*? nonl) "]") "{natbib}"))) + (unless (re-search-backward re nil t) + (insert + (format "\\usepackage%s{natbib}\n" + (if (null org-cite-natbib-options) + "" + (format "[%s]" + (mapconcat #'symbol-name + org-cite-natbib-options + ",")))))))) + (buffer-string))) + + +;;; Register `natbib' processor +(org-cite-register-processor 'natbib + :export-bibliography #'org-cite-natbib-export-bibliography + :export-citation #'org-cite-natbib-export-citation + :export-finalizer #'org-cite-natbib-use-package + :cite-styles + '((("author" "a") ("caps" "a") ("full" "f")) + (("noauthor" "na") ("bare" "b")) + (("text" "t") + ("bare" "b") ("caps" "c") ("full" "f") ("bare-caps" "bc") + ("bare-full" "bf") ("caps-full" "cf") ("bare-caps-full" "bcf")) + (("nil") + ("bare" "b") ("caps" "c") ("full" "f") ("bare-caps" "bc") + ("bare-full" "bf") ("caps-full" "cf") ("bare-caps-full" "bcf")))) + +(provide 'org-cite-natbib) +(provide 'oc-natbib) +;;; oc-natbib.el ends here