From 50db7f8ae94cf9a3799eccdf3d7ee69a2e7c4505 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20Simonyi?= Date: Mon, 11 Jul 2022 19:13:48 +0200 Subject: [PATCH] oc-csl.el: Add support for sub-bibliographies * lisp/oc-csl.el (org-cite-csl--rendered-bibliographies): New function to collect all #+print_bibliography keywords with their properties and call Citeproc to render all sub-bibliographies in one go as required by the API. Return the formatted bibliographies as values in an alist in which keys are the #+print_bibliography keyword options as plists. Cache the return value in the export communication channel. (org-cite-csl--bibliography-filter): New helper function to convert plists representing #+print_bibliography options to the alist filter form expected by Citeproc. (org-cite-csl--rendered-citations): Call `org-cite-csl--rendered-bibliographies' before rendering citations to make sure that the complete sub-bibliography information is added to the processor and, therefore, citation numbers are correct. (org-cite-csl--render-bibliography): Instead of directly calling Citeproc to render the bibliography, call `org-cite-csl--rendered-bibliographies' and retrieve the formatted bibliography from its return value based on the options passed as the `props' argument. --- etc/ORG-NEWS | 13 +++++++- lisp/oc-csl.el | 83 +++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 88 insertions(+), 8 deletions(-) diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS index 4cda357f1..ce8675dea 100644 --- a/etc/ORG-NEWS +++ b/etc/ORG-NEWS @@ -239,7 +239,7 @@ This behaviour can be changed by supplying a =:align= parameter. The tabbing environment can be useful when generating simple tables which can be span multiple pages and when table cells are allowed to overflow. -*** Support for =nocite= citations in the "csl" export processor +*** Support for =nocite= citations and sub-bibliographies in the "csl" export processor The "csl" citation export processor now supports =nocite= style citations that add items to the printed bibliography without visible @@ -251,6 +251,17 @@ instance, #+end_src includes all available items in the printed bibliography. + +The "csl" export processor now also supports sub-bibliographies that +show only a subset of the references based on some criterion. For +example, + +#+begin_src org +#+print_bibliography: :type book :keyword ai +#+end_src + +prints a sub-bibliography containing the book entries with =ai= among +their keywords. ** New functions and changes in function arguments *** New function ~org-element-cache-map~ for quick mapping across Org elements diff --git a/lisp/oc-csl.el b/lisp/oc-csl.el index a2bd6653c..0b2fe5c41 100644 --- a/lisp/oc-csl.el +++ b/lisp/oc-csl.el @@ -90,11 +90,23 @@ ;; The part of the suffix before the locator is appended to reference's prefix. ;; If no locator term is used, but a number is present, then "page" is assumed. +;; Filtered sub-bibliographies can be printed by passing filtering +;; options to the "print_bibliography" keywords. E.g., +;; +;; #+print_bibliography: :type book keyword: emacs +;; +;; If you need to use a key multiple times, you can separate its +;; values with commas, but without any space in-between: +;; +;; #+print_bibliography: :keyword abc,xyz :type article + ;; This library was heavily inspired by and borrows from AndrĂ¡s Simonyi's ;; Citeproc Org () library. ;; Many thanks to him! ;;; Code: +(require 'cl-lib) +(require 'map) (require 'bibtex) (require 'json) (require 'oc) @@ -559,6 +571,10 @@ OUTPUT using Citeproc." (citeproc-append-citations structures processor)) (when nocite-ids (citeproc-add-uncited nocite-ids processor)) + ;; All bibliographies have to be rendered in order to have + ;; correct citation numbers even if there are several + ;; sub-bibliograhies. + (org-cite-csl--rendered-bibliographies info) (let (result (rendered (citeproc-render-citations processor @@ -572,6 +588,62 @@ OUTPUT using Citeproc." (plist-put info :cite-citeproc-rendered-citations result) result)))) +(defun org-cite-csl--bibliography-filter (bib-props) + "Return the sub-bibliography filter corresponding to bibliography properties. + +BIB-PROPS should be a plist representing the properties +associated with a \"print_bibliography\" keyword, as returned by +`org-cite-bibliography-properties'." + (let (result + (remove-keyword-colon (lambda (x) (intern (substring (symbol-name x) 1))))) + (map-do + (lambda (key value) + (pcase key + ((or :keyword :notkeyword :nottype :notcsltype :filter) + (dolist (v (split-string value ",")) + (push (cons (funcall remove-keyword-colon key) v) result))) + ((or :type :csltype) + (if (string-match-p "," value) + (user-error "The \"%s\" print_bibliography option does not support comma-separated values" key) + (push (cons (funcall remove-keyword-colon key) value) result))))) + bib-props) + result)) + +(defun org-cite-csl--rendered-bibliographies (info) + "Return the rendered bibliographies. + +INFO is the export state, as a property list. + +Return an (OUTPUTS PARAMETERS) list where OUTPUTS is an alist +of (BIB-PROPS . OUTPUT) pairs where each key is a property list +of a \"print_bibliography\" keyword and the corresponding OUTPUT +value is the bibliography as rendered by Citeproc." + (or (plist-get info :cite-citeproc-rendered-bibliographies) + (let (bib-plists bib-filters) + ;; Collect bibliography property lists and the corresponding + ;; Citeproc sub-bib filters. + (org-element-map (plist-get info :parse-tree) 'keyword + (lambda (keyword) + (when (equal "PRINT_BIBLIOGRAPHY" (org-element-property :key keyword)) + (let ((bib-plist (org-cite-bibliography-properties keyword))) + (push bib-plist bib-plists) + (push (org-cite-csl--bibliography-filter bib-plist) bib-filters))))) + (setq bib-filters (nreverse bib-filters) + bib-plists (nreverse bib-plists)) + ;; Render and return all bibliographies. + (let ((processor (org-cite-csl--processor info))) + (citeproc-add-subbib-filters bib-filters processor) + (pcase-let* ((format (org-cite-csl--output-format info)) + (`(,rendered-bibs . ,parameters) + (citeproc-render-bib + (org-cite-csl--processor info) + format + (org-cite-csl--no-citelinks-p info))) + (outputs (cl-mapcar #'cons bib-plists rendered-bibs)) + (result (list outputs parameters))) + (plist-put info :cite-citeproc-rendered-bibliographies result) + result))))) + ;;; Export capability (defun org-cite-csl-render-citation (citation _style _backend info) @@ -585,16 +657,13 @@ INFO is the export state, as a property list." ;; process. (org-cite-parse-objects output)))) -(defun org-cite-csl-render-bibliography (_keys _files _style _props _backend info) +(defun org-cite-csl-render-bibliography (_keys _files _style props _backend info) "Export bibliography. INFO is the export state, as a property list." (org-cite-csl--barf-without-citeproc) - (pcase-let* ((format (org-cite-csl--output-format info)) - (`(,output . ,parameters) - (citeproc-render-bib - (org-cite-csl--processor info) - format - (org-cite-csl--no-citelinks-p info)))) + (pcase-let* ((format (org-cite-csl--output-format info)) + (`(,outputs ,parameters) (org-cite-csl--rendered-bibliographies info)) + (output (cdr (assoc props outputs)))) (pcase format ('html (concat -- 2.25.1