config

Personal configuration.
git clone git://code.dwrz.net/config
Log | Files | Refs

oc-natbib.el (8360B)


      1 ;;; oc-natbib.el --- Citation processor using natbib LaTeX package  -*- lexical-binding: t; -*-
      2 
      3 ;; Copyright (C) 2021-2024 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-ast" (property node))
     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 (defcustom org-cite-natbib-bibliography-style 'unsrtnat
     81   "Default bibliography style."
     82   :group 'org-cite
     83   :package-version '(Org . "9.7")
     84   :type
     85   '(choice
     86     (const unsrtnat)
     87     (symbol :tag "Other")))
     88 
     89 
     90 ;;; Internal functions
     91 (defun org-cite-natbib--style-to-command (style)
     92   "Return command name to use according to STYLE pair."
     93   (pcase style
     94     ;; "author" style.
     95     (`(,(or "author" "a") . ,variant)
     96      (pcase variant
     97        ((or "caps" "c")             "\\Citeauthor")
     98        ((or "full" "f")             "\\citeauthor*")
     99        (_                           "\\citeauthor")))
    100     ;; "noauthor" style.
    101     (`(,(or "noauthor" "na") . ,variant)
    102      (pcase variant
    103        ((or "bare" "b")             "\\citeyear")
    104        (_                           "\\citeyearpar")))
    105     ;; "nocite" style.
    106     (`(,(or "nocite" "n") . ,_)     "\\nocite")
    107     ;; "text" style.
    108     (`(,(or "text" "t") . ,variant)
    109      (pcase variant
    110        ((or "bare" "b")             "\\citealt")
    111        ((or "caps" "c")             "\\Citet")
    112        ((or "full" "f")             "\\citet*")
    113        ((or "bare-caps" "bc")       "\\Citealt")
    114        ((or "bare-full" "bf")       "\\citealt*")
    115        ((or "caps-full" "cf")       "\\Citet*")
    116        ((or "bare-caps-full" "bcf") "\\Citealt*")
    117        (_ "\\citet")))
    118     ;; Default ("nil") style.
    119     (`(,_ . ,variant)
    120      (pcase variant
    121        ((or "bare" "b")             "\\citealp")
    122        ((or "caps" "c")             "\\Citep")
    123        ((or "full" "f")             "\\citep*")
    124        ((or "bare-caps" "bc")       "\\Citealp")
    125        ((or "bare-full" "bf")       "\\citealp*")
    126        ((or "caps-full" "cf")       "\\Citep*")
    127        ((or "bare-caps-full" "bcf") "\\Citealp*")
    128        (_                           "\\citep")))
    129     ;; This should not happen.
    130     (_ (error "Invalid style: %S" style))))
    131 
    132 (defun org-cite-natbib--build-optional-arguments (citation info)
    133   "Build optional arguments for citation command.
    134 CITATION is the citation object.  INFO is the export state, as a property list."
    135   (pcase-let ((`(,prefix . ,suffix) (org-cite-main-affixes citation)))
    136     (concat (and prefix (format "[%s]" (org-trim (org-export-data prefix info))))
    137             (cond
    138              (suffix (format "[%s]" (org-trim (org-export-data suffix info))))
    139              (prefix "[]")
    140              (t nil)))))
    141 
    142 (defun org-cite-natbib--build-arguments (citation)
    143   "Build arguments for citation command for CITATION object."
    144   (format "{%s}"
    145           (mapconcat #'identity
    146                      (org-cite-get-references citation t)
    147                      ",")))
    148 
    149 
    150 ;;; Export capability
    151 (defun org-cite-natbib-export-bibliography (_keys files style &rest _)
    152   "Print references from bibliography FILES.
    153 FILES is a list of absolute file names.  STYLE is the bibliography style, as
    154 a string or nil."
    155   (concat
    156    (format "\\bibliographystyle{%s}\n"
    157            (or style org-cite-natbib-bibliography-style))
    158    (format "\\bibliography{%s}"
    159            (mapconcat #'file-name-sans-extension
    160                       files
    161                       ","))))
    162 
    163 (defun org-cite-natbib-export-citation (citation style _ info)
    164   "Export CITATION object.
    165 STYLE is the citation style, as a pair of strings or nil.  INFO is the export
    166 state, as a property list."
    167   (concat (org-cite-natbib--style-to-command style)
    168           (org-cite-natbib--build-optional-arguments citation info)
    169           (org-cite-natbib--build-arguments citation)))
    170 
    171 (defun org-cite-natbib-use-package (output &rest _)
    172   "Ensure output requires \"natbib\" package.
    173 OUTPUT is the final output of the export process."
    174   (with-temp-buffer
    175     (save-excursion (insert output))
    176     (when (search-forward "\\begin{document}" nil t)
    177       ;; Ensure there is a \usepackage{natbib} somewhere or add one.
    178       (goto-char (match-beginning 0))
    179       (let ((re (rx "\\usepackage" (opt "[" (*? nonl) "]") "{natbib}")))
    180         (unless (re-search-backward re nil t)
    181           (insert
    182            (format "\\usepackage%s{natbib}\n"
    183                    (if (null org-cite-natbib-options)
    184                        ""
    185                      (format "[%s]"
    186                              (mapconcat #'symbol-name
    187                                         org-cite-natbib-options
    188                                         ","))))))))
    189     (buffer-string)))
    190 
    191 
    192 ;;; Register `natbib' processor
    193 (org-cite-register-processor 'natbib
    194   :export-bibliography #'org-cite-natbib-export-bibliography
    195   :export-citation #'org-cite-natbib-export-citation
    196   :export-finalizer #'org-cite-natbib-use-package
    197   :cite-styles
    198   '((("author" "a") ("caps" "a") ("full" "f"))
    199     (("noauthor" "na") ("bare" "b"))
    200     (("text" "t")
    201      ("bare" "b") ("caps" "c") ("full" "f") ("bare-caps" "bc")
    202      ("bare-full" "bf") ("caps-full" "cf") ("bare-caps-full" "bcf"))
    203     (("nil")
    204      ("bare" "b") ("caps" "c") ("full" "f") ("bare-caps" "bc")
    205      ("bare-full" "bf") ("caps-full" "cf") ("bare-caps-full" "bcf"))))
    206 
    207 (provide 'oc-natbib)
    208 ;;; oc-natbib.el ends here