dotemacs

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

oc-natbib.el (8135B)


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