dotemacs

My Emacs configuration
git clone git://git.entf.net/dotemacs
Log | Files | Refs | LICENSE

oc-natbib.el (8250B)


      1 ;;; oc-natbib.el --- Citation processor using natbib LaTeX package  -*- lexical-binding: t; -*-
      2 
      3 ;; Copyright (C) 2021 Free Software Foundation, Inc.
      4 
      5 ;; Author: Nicolas Goaziou <mail@nicolasgoaziou.fr>
      6 
      7 ;; This program is free software; you can redistribute it and/or modify
      8 ;; it under the terms of the GNU General Public License as published by
      9 ;; the Free Software Foundation, either version 3 of the License, or
     10 ;; (at your option) any later version.
     11 
     12 ;; This program is distributed in the hope that it will be useful,
     13 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 ;; GNU General Public License for more details.
     16 
     17 ;; You should have received a copy of the GNU General Public License
     18 ;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
     19 
     20 ;;; Commentary:
     21 
     22 ;; This library registers the `natbib' citation processor, which provides the
     23 ;; "export" capability for citations.
     24 
     25 ;; The processor relies on "natbib" LaTeX package.  As such it ensures that the
     26 ;; package is properly required in the document's preamble.  More accurately, it
     27 ;; will use any "\\usepackage{natbib}" command already present in the document
     28 ;; (e.g., through `org-latex-packages-alist'), or insert one using options
     29 ;; defined in `org-cite-natbib-options'.
     30 
     31 ;; It supports the following citation styles:
     32 ;;
     33 ;; - author (a), including caps (c), and full (f) variants,
     34 ;; - noauthor (na), including bare (b) variant,
     35 ;; - text (t), including bare (b), caps (c), full (f), bare-caps (bc),
     36 ;;   bare-full (bf), caps-full (cf), and bare-caps-full (bcf) variants,
     37 ;; - default, including bare (b), caps (c), full (f), bare-caps (bc),
     38 ;;   bare-full (bf), caps-full (cf), and bare-caps-full (bcf) variants.
     39 
     40 ;; Bibliography accepts any style supported by "natbib" package.
     41 
     42 ;;; Code:
     43 (require 'oc)
     44 
     45 (declare-function org-element-property "org-element" (property element))
     46 
     47 (declare-function org-export-data "org-export" (data info))
     48 
     49 
     50 ;;; Customization
     51 (defcustom org-cite-natbib-options nil
     52   "List of options added to \"natbib\" package.
     53 If \"natbib\" package is already required in the document, e.g., through
     54 `org-latex-packages-alist' variable, these options are ignored."
     55   :group 'org-cite
     56   :package-version '(Org . "9.5")
     57   :type
     58   '(set
     59     (const :tag "use round parentheses (default)" round)
     60     (const :tag "use square brackets" square)
     61     (const :tag "use curly braces" curly)
     62     (const :tag "use angle brackets" angle)
     63     (const :tag "separate multiple citations with colons (default)" colon)
     64     (const :tag "separate multiple citations with comas" comma)
     65     (const :tag "generate author-year citations" authoryear)
     66     (const :tag "generate numerical citations" numbers)
     67     (const :tag "generate superscripted numerical citations" super)
     68     (const :tag "order multiple citations according to the list of references" sort)
     69     (const :tag "order as above, but numerical citations are compressed if possible" sort&compress)
     70     (const :tag "display full author list on first citation, abbreviate the others" longnamesfirst)
     71     (const :tag "redefine \\thebibliography to issue \\section* instead of \\chapter*" sectionbib)
     72     (const :tag "keep all the authors' names in a citation on one line" nonamebreak))
     73   :safe t)
     74 
     75 
     76 ;;; Internal functions
     77 (defun org-cite-natbib--style-to-command (style)
     78   "Return command name to use according to STYLE pair."
     79   (pcase style
     80     ;; "author" style.
     81     (`(,(or "author" "a") . ,variant)
     82      (pcase variant
     83        ((or "caps" "c")             "\\Citeauthor")
     84        ((or "full" "f")             "\\citeauthor*")
     85        (_                           "\\citeauthor")))
     86     ;; "noauthor" style.
     87     (`(,(or "noauthor" "na") . ,variant)
     88      (pcase variant
     89        ((or "bare" "b")             "\\citeyear")
     90        (_                           "\\citeyearpar")))
     91     ;; "nocite" style.
     92     (`(,(or "nocite" "n") . ,_)     "\\nocite")
     93     ;; "text" style.
     94     (`(,(or "text" "t") . ,variant)
     95      (pcase variant
     96        ((or "bare" "b")             "\\citealt")
     97        ((or "caps" "c")             "\\Citet")
     98        ((or "full" "f")             "\\citet*")
     99        ((or "bare-caps" "bc")       "\\Citealt")
    100        ((or "bare-full" "bf")       "\\citealt*")
    101        ((or "caps-full" "cf")       "\\Citet*")
    102        ((or "bare-caps-full" "bcf") "\\Citealt*")
    103        (_ "\\citet")))
    104     ;; Default ("nil") style.
    105     (`(,_ . ,variant)
    106      (pcase variant
    107        ((or "bare" "b")             "\\citealp")
    108        ((or "caps" "c")             "\\Citep")
    109        ((or "full" "f")             "\\citep*")
    110        ((or "bare-caps" "bc")       "\\Citealp")
    111        ((or "bare-full" "bf")       "\\citealp*")
    112        ((or "caps-full" "cf")       "\\Citep*")
    113        ((or "bare-caps-full" "bcf") "\\Citealp*")
    114        (_                           "\\citep")))
    115     ;; This should not happen.
    116     (_ (error "Invalid style: %S" style))))
    117 
    118 (defun org-cite-natbib--build-optional-arguments (citation info)
    119   "Build optional arguments for citation command.
    120 CITATION is the citation object.  INFO is the export state, as a property list."
    121   (let* ((origin (pcase (org-cite-get-references citation)
    122                    (`(,reference) reference)
    123                    (_ citation)))
    124          (suffix (org-element-property :suffix origin))
    125          (prefix (org-element-property :prefix origin)))
    126     (concat (and prefix (format "[%s]" (org-trim (org-export-data prefix info))))
    127             (cond
    128              (suffix (format "[%s]" (org-trim (org-export-data suffix info))))
    129              (prefix "[]")
    130              (t nil)))))
    131 
    132 (defun org-cite-natbib--build-arguments (citation)
    133   "Build arguments for citation command for CITATION object."
    134   (format "{%s}"
    135           (mapconcat #'identity
    136                      (org-cite-get-references citation t)
    137                      ",")))
    138 
    139 
    140 ;;; Export capability
    141 (defun org-cite-natbib-export-bibliography (_keys files style &rest _)
    142   "Print references from bibliography FILES.
    143 FILES is a list of absolute file names.  STYLE is the bibliography style, as
    144 a string or nil."
    145   (concat (and style (format "\\bibliographystyle{%s}\n" style))
    146           (format "\\bibliography{%s}"
    147                   (mapconcat #'file-name-sans-extension
    148                              files
    149                              ","))))
    150 
    151 (defun org-cite-natbib-export-citation (citation style _ info)
    152   "Export CITATION object.
    153 STYLE is the citation style, as a pair of strings or nil.  INFO is the export
    154 state, as a property list."
    155   (concat (org-cite-natbib--style-to-command style)
    156           (org-cite-natbib--build-optional-arguments citation info)
    157           (org-cite-natbib--build-arguments citation)))
    158 
    159 (defun org-cite-natbib-use-package (output &rest _)
    160   "Ensure output requires \"natbib\" package.
    161 OUTPUT is the final output of the export process."
    162   (with-temp-buffer
    163     (save-excursion (insert output))
    164     (when (search-forward "\\begin{document}" nil t)
    165       ;; Ensure there is a \usepackage{natbib} somewhere or add one.
    166       (goto-char (match-beginning 0))
    167       (let ((re (rx "\\usepackage" (opt "[" (*? nonl) "]") "{natbib}")))
    168         (unless (re-search-backward re nil t)
    169           (insert
    170            (format "\\usepackage%s{natbib}\n"
    171                    (if (null org-cite-natbib-options)
    172                        ""
    173                      (format "[%s]"
    174                              (mapconcat #'symbol-name
    175                                         org-cite-natbib-options
    176                                         ","))))))))
    177     (buffer-string)))
    178 
    179 
    180 ;;; Register `natbib' processor
    181 (org-cite-register-processor 'natbib
    182   :export-bibliography #'org-cite-natbib-export-bibliography
    183   :export-citation #'org-cite-natbib-export-citation
    184   :export-finalizer #'org-cite-natbib-use-package
    185   :cite-styles
    186   '((("author" "a") ("caps" "a") ("full" "f"))
    187     (("noauthor" "na") ("bare" "b"))
    188     (("text" "t")
    189      ("bare" "b") ("caps" "c") ("full" "f") ("bare-caps" "bc")
    190      ("bare-full" "bf") ("caps-full" "cf") ("bare-caps-full" "bcf"))
    191     (("nil")
    192      ("bare" "b") ("caps" "c") ("full" "f") ("bare-caps" "bc")
    193      ("bare-full" "bf") ("caps-full" "cf") ("bare-caps-full" "bcf"))))
    194 
    195 (provide 'oc-natbib)
    196 ;;; oc-natbib.el ends here