diff options
author | Nicolas Goaziou <mail@nicolasgoaziou.fr> | 2021-05-26 21:54:00 +0200 |
---|---|---|
committer | Nicolas Goaziou <mail@nicolasgoaziou.fr> | 2021-07-09 08:47:14 +0200 |
commit | 971c1359a56b75881fe61b75ab85e6781bb2bec6 (patch) | |
tree | 17ffc89192f00e41078448951b4593c2bc657a7f | |
parent | ae5f5151fe5283045ae7c0542ef88c24e369920a (diff) | |
download | org-mode-971c1359a56b75881fe61b75ab85e6781bb2bec6.tar.gz |
oc-csl: Implement `csl' citation processor
* etc/csl/chicago-author-date.csl:
* etc/csl/locales-en-US.xml:
* lisp/oc-csl.el (csl): New files.
* etc/Makefile (ETCDIRS): Register new files.
-rw-r--r-- | etc/Makefile | 2 | ||||
-rw-r--r-- | etc/csl/chicago-author-date.csl | 644 | ||||
-rw-r--r-- | etc/csl/locales-en-US.xml | 348 | ||||
-rw-r--r-- | lisp/oc-csl.el | 603 |
4 files changed, 1596 insertions, 1 deletions
diff --git a/etc/Makefile b/etc/Makefile index 8b06158..ab5c988 100644 --- a/etc/Makefile +++ b/etc/Makefile @@ -1,4 +1,4 @@ -ETCDIRS = styles schema +ETCDIRS = styles schema csl -include local.mk # optional local customization .NOTPARALLEL: # always run this make serially diff --git a/etc/csl/chicago-author-date.csl b/etc/csl/chicago-author-date.csl new file mode 100644 index 0000000..d066efa --- /dev/null +++ b/etc/csl/chicago-author-date.csl @@ -0,0 +1,644 @@ +<?xml version="1.0" encoding="utf-8"?> +<style xmlns="http://purl.org/net/xbiblio/csl" class="in-text" version="1.0" demote-non-dropping-particle="display-and-sort" page-range-format="chicago"> + <info> + <title>Chicago Manual of Style 17th edition (author-date)</title> + <id>http://www.zotero.org/styles/chicago-author-date</id> + <link href="http://www.zotero.org/styles/chicago-author-date" rel="self"/> + <link href="http://www.chicagomanualofstyle.org/tools_citationguide.html" rel="documentation"/> + <author> + <name>Julian Onions</name> + <email>julian.onions@gmail.com</email> + </author> + <contributor> + <name>Sebastian Karcher</name> + </contributor> + <contributor> + <name>Richard Karnesky</name> + <email>karnesky+zotero@gmail.com</email> + <uri>http://arc.nucapt.northwestern.edu/Richard_Karnesky</uri> + </contributor> + <contributor> + <name>Andrew Dunning</name> + <email>andrew.dunning@utoronto.ca</email> + </contributor> + <category citation-format="author-date"/> + <category field="generic-base"/> + <summary>The author-date variant of the Chicago style</summary> + <updated>2017-10-12T12:00:00+00:00</updated> + <rights license="http://creativecommons.org/licenses/by-sa/3.0/">This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License</rights> + </info> + <locale xml:lang="en"> + <terms> + <term name="editor" form="verb-short">ed.</term> + <term name="container-author" form="verb">by</term> + <term name="translator" form="verb-short">trans.</term> + <term name="editortranslator" form="verb"> + <single>edited and translated by</single> + <multiple>edited and translated by</multiple> + </term> + <term name="translator" form="short">trans.</term> + </terms> + </locale> + <macro name="secondary-contributors"> + <choose> + <if type="chapter paper-conference" match="none"> + <group delimiter=". "> + <names variable="editor translator" delimiter=". "> + <label form="verb" text-case="capitalize-first" suffix=" "/> + <name and="text" delimiter=", "/> + </names> + <names variable="director" delimiter=". "> + <label form="verb" text-case="capitalize-first" suffix=" "/> + <name and="text" delimiter=", "/> + </names> + </group> + </if> + </choose> + </macro> + <macro name="container-contributors"> + <choose> + <if type="chapter paper-conference" match="any"> + <group prefix=", " delimiter=", "> + <names variable="container-author" delimiter=", "> + <label form="verb" suffix=" "/> + <name and="text" delimiter=", "/> + </names> + <names variable="editor translator" delimiter=", "> + <label form="verb" suffix=" "/> + <name and="text" delimiter=", "/> + </names> + </group> + </if> + </choose> + </macro> + <macro name="editor"> + <names variable="editor"> + <name name-as-sort-order="first" and="text" sort-separator=", " delimiter=", " delimiter-precedes-last="always"/> + <label form="short" prefix=", "/> + </names> + </macro> + <macro name="translator"> + <names variable="translator"> + <name name-as-sort-order="first" and="text" sort-separator=", " delimiter=", " delimiter-precedes-last="always"/> + <label form="short" prefix=", "/> + </names> + </macro> + <macro name="recipient"> + <choose> + <if type="personal_communication"> + <choose> + <if variable="genre"> + <text variable="genre" text-case="capitalize-first"/> + </if> + <else> + <text term="letter" text-case="capitalize-first"/> + </else> + </choose> + </if> + </choose> + <names variable="recipient" delimiter=", "> + <label form="verb" prefix=" " text-case="lowercase" suffix=" "/> + <name and="text" delimiter=", "/> + </names> + </macro> + <macro name="substitute-title"> + <choose> + <if type="article-magazine article-newspaper review review-book" match="any"> + <text macro="container-title"/> + </if> + </choose> + </macro> + <macro name="contributors"> + <group delimiter=". "> + <names variable="author"> + <name and="text" name-as-sort-order="first" sort-separator=", " delimiter=", " delimiter-precedes-last="always"/> + <label form="short" prefix=", "/> + <substitute> + <names variable="editor"/> + <names variable="translator"/> + <names variable="director"/> + <text macro="substitute-title"/> + <text macro="title"/> + </substitute> + </names> + <text macro="recipient"/> + </group> + </macro> + <macro name="contributors-short"> + <names variable="author"> + <name form="short" and="text" delimiter=", " initialize-with=". "/> + <substitute> + <names variable="editor"/> + <names variable="translator"/> + <names variable="director"/> + <text macro="substitute-title"/> + <text macro="title"/> + </substitute> + </names> + </macro> + <macro name="interviewer"> + <names variable="interviewer" delimiter=", "> + <label form="verb" prefix=" " text-case="capitalize-first" suffix=" "/> + <name and="text" delimiter=", "/> + </names> + </macro> + <macro name="archive"> + <group delimiter=". "> + <text variable="archive_location" text-case="capitalize-first"/> + <text variable="archive"/> + <text variable="archive-place"/> + </group> + </macro> + <macro name="access"> + <group delimiter=". "> + <choose> + <if type="graphic report" match="any"> + <text macro="archive"/> + </if> + <else-if type="article-journal bill book chapter legal_case legislation motion_picture paper-conference" match="none"> + <text macro="archive"/> + </else-if> + </choose> + <choose> + <if type="webpage post-weblog" match="any"> + <date variable="issued" form="text"/> + </if> + </choose> + <choose> + <if variable="issued" match="none"> + <group delimiter=" "> + <text term="accessed" text-case="capitalize-first"/> + <date variable="accessed" form="text"/> + </group> + </if> + </choose> + <choose> + <if type="legal_case" match="none"> + <choose> + <if variable="DOI"> + <text variable="DOI" prefix="https://doi.org/"/> + </if> + <else> + <text variable="URL"/> + </else> + </choose> + </if> + </choose> + </group> + </macro> + <macro name="title"> + <choose> + <if variable="title" match="none"> + <choose> + <if type="personal_communication" match="none"> + <text variable="genre" text-case="capitalize-first"/> + </if> + </choose> + </if> + <else-if type="bill book graphic legislation motion_picture song" match="any"> + <text variable="title" text-case="title" font-style="italic"/> + <group prefix=" (" suffix=")" delimiter=" "> + <text term="version"/> + <text variable="version"/> + </group> + </else-if> + <else-if variable="reviewed-author"> + <choose> + <if variable="reviewed-title"> + <group delimiter=". "> + <text variable="title" text-case="title" quotes="true"/> + <group delimiter=", "> + <text variable="reviewed-title" text-case="title" font-style="italic" prefix="Review of "/> + <names variable="reviewed-author"> + <label form="verb-short" text-case="lowercase" suffix=" "/> + <name and="text" delimiter=", "/> + </names> + </group> + </group> + </if> + <else> + <group delimiter=", "> + <text variable="title" text-case="title" font-style="italic" prefix="Review of "/> + <names variable="reviewed-author"> + <label form="verb-short" text-case="lowercase" suffix=" "/> + <name and="text" delimiter=", "/> + </names> + </group> + </else> + </choose> + </else-if> + <else-if type="legal_case interview patent" match="any"> + <text variable="title"/> + </else-if> + <else> + <text variable="title" text-case="title" quotes="true"/> + </else> + </choose> + </macro> + <macro name="edition"> + <choose> + <if type="bill book graphic legal_case legislation motion_picture report song" match="any"> + <choose> + <if is-numeric="edition"> + <group delimiter=" " prefix=". "> + <number variable="edition" form="ordinal"/> + <text term="edition" form="short" strip-periods="true"/> + </group> + </if> + <else> + <text variable="edition" text-case="capitalize-first" prefix=". "/> + </else> + </choose> + </if> + <else-if type="chapter paper-conference" match="any"> + <choose> + <if is-numeric="edition"> + <group delimiter=" " prefix=", "> + <number variable="edition" form="ordinal"/> + <text term="edition" form="short"/> + </group> + </if> + <else> + <text variable="edition" prefix=", "/> + </else> + </choose> + </else-if> + </choose> + </macro> + <macro name="locators"> + <choose> + <if type="article-journal"> + <choose> + <if variable="volume"> + <text variable="volume" prefix=" "/> + <group prefix=" (" suffix=")"> + <choose> + <if variable="issue"> + <text variable="issue"/> + </if> + <else> + <date variable="issued"> + <date-part name="month"/> + </date> + </else> + </choose> + </group> + </if> + <else-if variable="issue"> + <group delimiter=" " prefix=", "> + <text term="issue" form="short"/> + <text variable="issue"/> + <date variable="issued" prefix="(" suffix=")"> + <date-part name="month"/> + </date> + </group> + </else-if> + <else> + <date variable="issued" prefix=", "> + <date-part name="month"/> + </date> + </else> + </choose> + </if> + <else-if type="legal_case"> + <text variable="volume" prefix=", "/> + <text variable="container-title" prefix=" "/> + <text variable="page" prefix=" "/> + </else-if> + <else-if type="bill book graphic legal_case legislation motion_picture report song" match="any"> + <group prefix=". " delimiter=". "> + <group> + <text term="volume" form="short" text-case="capitalize-first" suffix=" "/> + <number variable="volume" form="numeric"/> + </group> + <group> + <number variable="number-of-volumes" form="numeric"/> + <text term="volume" form="short" prefix=" " plural="true"/> + </group> + </group> + </else-if> + <else-if type="chapter paper-conference" match="any"> + <choose> + <if variable="page" match="none"> + <group prefix=". "> + <text term="volume" form="short" text-case="capitalize-first" suffix=" "/> + <number variable="volume" form="numeric"/> + </group> + </if> + </choose> + </else-if> + </choose> + </macro> + <macro name="locators-chapter"> + <choose> + <if type="chapter paper-conference" match="any"> + <choose> + <if variable="page"> + <group prefix=", "> + <text variable="volume" suffix=":"/> + <text variable="page"/> + </group> + </if> + </choose> + </if> + </choose> + </macro> + <macro name="locators-article"> + <choose> + <if type="article-newspaper"> + <group prefix=", " delimiter=", "> + <group delimiter=" "> + <text variable="edition"/> + <text term="edition"/> + </group> + <group> + <text term="section" form="short" suffix=" "/> + <text variable="section"/> + </group> + </group> + </if> + <else-if type="article-journal"> + <choose> + <if variable="volume issue" match="any"> + <text variable="page" prefix=":"/> + </if> + <else> + <text variable="page" prefix=", "/> + </else> + </choose> + </else-if> + </choose> + </macro> + <macro name="point-locators"> + <choose> + <if variable="locator"> + <choose> + <if locator="page" match="none"> + <choose> + <if type="bill book graphic legal_case legislation motion_picture report song" match="any"> + <choose> + <if variable="volume"> + <group> + <text term="volume" form="short" suffix=" "/> + <number variable="volume" form="numeric"/> + <label variable="locator" form="short" prefix=", " suffix=" "/> + </group> + </if> + <else> + <label variable="locator" form="short" suffix=" "/> + </else> + </choose> + </if> + <else> + <label variable="locator" form="short" suffix=" "/> + </else> + </choose> + </if> + <else-if type="bill book graphic legal_case legislation motion_picture report song" match="any"> + <number variable="volume" form="numeric" suffix=":"/> + </else-if> + </choose> + <text variable="locator"/> + </if> + </choose> + </macro> + <macro name="container-prefix"> + <text term="in" text-case="capitalize-first"/> + </macro> + <macro name="container-title"> + <choose> + <if type="chapter paper-conference" match="any"> + <text macro="container-prefix" suffix=" "/> + </if> + </choose> + <choose> + <if type="webpage"> + <text variable="container-title" text-case="title"/> + </if> + <else-if type="legal_case" match="none"> + <group delimiter=" "> + <text variable="container-title" text-case="title" font-style="italic"/> + <choose> + <if type="post-weblog"> + <text value="(blog)"/> + </if> + </choose> + </group> + </else-if> + </choose> + </macro> + <macro name="publisher"> + <group delimiter=": "> + <text variable="publisher-place"/> + <text variable="publisher"/> + </group> + </macro> + <macro name="date"> + <choose> + <if variable="issued"> + <group delimiter=" "> + <date variable="original-date" form="text" date-parts="year" prefix="(" suffix=")"/> + <date variable="issued"> + <date-part name="year"/> + </date> + </group> + </if> + <else-if variable="status"> + <text variable="status" text-case="capitalize-first"/> + </else-if> + <else> + <text term="no date" form="short"/> + </else> + </choose> + </macro> + <macro name="date-in-text"> + <choose> + <if variable="issued"> + <group delimiter=" "> + <date variable="original-date" form="text" date-parts="year" prefix="[" suffix="]"/> + <date variable="issued"> + <date-part name="year"/> + </date> + </group> + </if> + <else-if variable="status"> + <text variable="status"/> + </else-if> + <else> + <text term="no date" form="short"/> + </else> + </choose> + </macro> + <macro name="day-month"> + <date variable="issued"> + <date-part name="month"/> + <date-part name="day" prefix=" "/> + </date> + </macro> + <macro name="collection-title"> + <choose> + <if match="none" type="article-journal"> + <choose> + <if match="none" is-numeric="collection-number"> + <group delimiter=", "> + <text variable="collection-title" text-case="title"/> + <text variable="collection-number"/> + </group> + </if> + <else> + <group delimiter=" "> + <text variable="collection-title" text-case="title"/> + <text variable="collection-number"/> + </group> + </else> + </choose> + </if> + </choose> + </macro> + <macro name="collection-title-journal"> + <choose> + <if type="article-journal"> + <group delimiter=" "> + <text variable="collection-title"/> + <text variable="collection-number"/> + </group> + </if> + </choose> + </macro> + <macro name="event"> + <group> + <text term="presented at" suffix=" "/> + <text variable="event"/> + </group> + </macro> + <macro name="description"> + <choose> + <if type="interview"> + <group delimiter=". "> + <text macro="interviewer"/> + <text variable="medium" text-case="capitalize-first"/> + </group> + </if> + <else-if type="patent"> + <group delimiter=" " prefix=". "> + <text variable="authority"/> + <text variable="number"/> + </group> + </else-if> + <else> + <text variable="medium" text-case="capitalize-first" prefix=". "/> + </else> + </choose> + <choose> + <if variable="title" match="none"/> + <else-if type="thesis personal_communication speech" match="any"/> + <else> + <group delimiter=" " prefix=". "> + <text variable="genre" text-case="capitalize-first"/> + <choose> + <if type="report"> + <text variable="number"/> + </if> + </choose> + </group> + </else> + </choose> + </macro> + <macro name="issue"> + <choose> + <if type="legal_case"> + <text variable="authority" prefix=". "/> + </if> + <else-if type="speech"> + <group prefix=". " delimiter=", "> + <group delimiter=" "> + <text variable="genre" text-case="capitalize-first"/> + <text macro="event"/> + </group> + <text variable="event-place"/> + <text macro="day-month"/> + </group> + </else-if> + <else-if type="article-newspaper article-magazine personal_communication" match="any"> + <date variable="issued" form="text" prefix=", "/> + </else-if> + <else-if type="patent"> + <group delimiter=", " prefix=", "> + <group delimiter=" "> + <!--Needs Localization--> + <text value="filed"/> + <date variable="submitted" form="text"/> + </group> + <group delimiter=" "> + <choose> + <if variable="issued submitted" match="all"> + <text term="and"/> + </if> + </choose> + <!--Needs Localization--> + <text value="issued"/> + <date variable="issued" form="text"/> + </group> + </group> + </else-if> + <else> + <group prefix=". " delimiter=", "> + <choose> + <if type="thesis"> + <text variable="genre" text-case="capitalize-first"/> + </if> + </choose> + <text macro="publisher"/> + </group> + </else> + </choose> + </macro> + <citation et-al-min="4" et-al-use-first="1" disambiguate-add-year-suffix="true" disambiguate-add-names="true" disambiguate-add-givenname="true" givenname-disambiguation-rule="primary-name" collapse="year"> + <layout prefix="(" suffix=")" delimiter="; "> + <group delimiter=", "> + <choose> + <if variable="issued accessed" match="any"> + <group delimiter=" "> + <text macro="contributors-short"/> + <text macro="date-in-text"/> + </group> + </if> + <!---comma before forthcoming and n.d.--> + <else> + <group delimiter=", "> + <text macro="contributors-short"/> + <text macro="date-in-text"/> + </group> + </else> + </choose> + <text macro="point-locators"/> + </group> + </layout> + </citation> + <bibliography hanging-indent="true" et-al-min="11" et-al-use-first="7" subsequent-author-substitute="———" entry-spacing="0"> + <sort> + <key macro="contributors"/> + <key variable="issued"/> + <key variable="title"/> + </sort> + <layout suffix="."> + <group delimiter=". "> + <text macro="contributors"/> + <text macro="date"/> + <text macro="title"/> + </group> + <text macro="description"/> + <text macro="secondary-contributors" prefix=". "/> + <text macro="container-title" prefix=". "/> + <text macro="container-contributors"/> + <text macro="edition"/> + <text macro="locators-chapter"/> + <text macro="collection-title-journal" prefix=", " suffix=", "/> + <text macro="locators"/> + <text macro="collection-title" prefix=". "/> + <text macro="issue"/> + <text macro="locators-article"/> + <text macro="access" prefix=". "/> + </layout> + </bibliography> +</style> diff --git a/etc/csl/locales-en-US.xml b/etc/csl/locales-en-US.xml new file mode 100644 index 0000000..a5e95df --- /dev/null +++ b/etc/csl/locales-en-US.xml @@ -0,0 +1,348 @@ +<?xml version="1.0" encoding="utf-8"?> +<locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0" xml:lang="en-US"> + <info> + <rights license="http://creativecommons.org/licenses/by-sa/3.0/">This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License</rights> + <updated>2015-10-10T23:31:02+00:00</updated> + </info> + <style-options punctuation-in-quote="true"/> + <date form="text"> + <date-part name="month" suffix=" "/> + <date-part name="day" suffix=", "/> + <date-part name="year"/> + </date> + <date form="numeric"> + <date-part name="month" form="numeric-leading-zeros" suffix="/"/> + <date-part name="day" form="numeric-leading-zeros" suffix="/"/> + <date-part name="year"/> + </date> + <terms> + <term name="accessed">accessed</term> + <term name="and">and</term> + <term name="and others">and others</term> + <term name="anonymous">anonymous</term> + <term name="anonymous" form="short">anon.</term> + <term name="at">at</term> + <term name="available at">available at</term> + <term name="by">by</term> + <term name="circa">circa</term> + <term name="circa" form="short">c.</term> + <term name="cited">cited</term> + <term name="edition"> + <single>edition</single> + <multiple>editions</multiple> + </term> + <term name="edition" form="short">ed.</term> + <term name="et-al">et al.</term> + <term name="forthcoming">forthcoming</term> + <term name="from">from</term> + <term name="ibid">ibid.</term> + <term name="in">in</term> + <term name="in press">in press</term> + <term name="internet">internet</term> + <term name="interview">interview</term> + <term name="letter">letter</term> + <term name="no date">no date</term> + <term name="no date" form="short">n.d.</term> + <term name="online">online</term> + <term name="presented at">presented at the</term> + <term name="reference"> + <single>reference</single> + <multiple>references</multiple> + </term> + <term name="reference" form="short"> + <single>ref.</single> + <multiple>refs.</multiple> + </term> + <term name="retrieved">retrieved</term> + <term name="scale">scale</term> + <term name="version">version</term> + + <!-- ANNO DOMINI; BEFORE CHRIST --> + <term name="ad">AD</term> + <term name="bc">BC</term> + + <!-- PUNCTUATION --> + <term name="open-quote">“</term> + <term name="close-quote">”</term> + <term name="open-inner-quote">‘</term> + <term name="close-inner-quote">’</term> + <term name="page-range-delimiter">–</term> + + <!-- ORDINALS --> + <term name="ordinal">th</term> + <term name="ordinal-01">st</term> + <term name="ordinal-02">nd</term> + <term name="ordinal-03">rd</term> + <term name="ordinal-11">th</term> + <term name="ordinal-12">th</term> + <term name="ordinal-13">th</term> + + <!-- LONG ORDINALS --> + <term name="long-ordinal-01">first</term> + <term name="long-ordinal-02">second</term> + <term name="long-ordinal-03">third</term> + <term name="long-ordinal-04">fourth</term> + <term name="long-ordinal-05">fifth</term> + <term name="long-ordinal-06">sixth</term> + <term name="long-ordinal-07">seventh</term> + <term name="long-ordinal-08">eighth</term> + <term name="long-ordinal-09">ninth</term> + <term name="long-ordinal-10">tenth</term> + + <!-- LONG LOCATOR FORMS --> + <term name="book"> + <single>book</single> + <multiple>books</multiple> + </term> + <term name="chapter"> + <single>chapter</single> + <multiple>chapters</multiple> + </term> + <term name="column"> + <single>column</single> + <multiple>columns</multiple> + </term> + <term name="figure"> + <single>figure</single> + <multiple>figures</multiple> + </term> + <term name="folio"> + <single>folio</single> + <multiple>folios</multiple> + </term> + <term name="issue"> + <single>number</single> + <multiple>numbers</multiple> + </term> + <term name="line"> + <single>line</single> + <multiple>lines</multiple> + </term> + <term name="note"> + <single>note</single> + <multiple>notes</multiple> + </term> + <term name="opus"> + <single>opus</single> + <multiple>opera</multiple> + </term> + <term name="page"> + <single>page</single> + <multiple>pages</multiple> + </term> + <term name="number-of-pages"> + <single>page</single> + <multiple>pages</multiple> + </term> + <term name="paragraph"> + <single>paragraph</single> + <multiple>paragraphs</multiple> + </term> + <term name="part"> + <single>part</single> + <multiple>parts</multiple> + </term> + <term name="section"> + <single>section</single> + <multiple>sections</multiple> + </term> + <term name="sub verbo"> + <single>sub verbo</single> + <multiple>sub verbis</multiple> + </term> + <term name="verse"> + <single>verse</single> + <multiple>verses</multiple> + </term> + <term name="volume"> + <single>volume</single> + <multiple>volumes</multiple> + </term> + + <!-- SHORT LOCATOR FORMS --> + <term name="book" form="short"> + <single>bk.</single> + <multiple>bks.</multiple> + </term> + <term name="chapter" form="short"> + <single>chap.</single> + <multiple>chaps.</multiple> + </term> + <term name="column" form="short"> + <single>col.</single> + <multiple>cols.</multiple> + </term> + <term name="figure" form="short"> + <single>fig.</single> + <multiple>figs.</multiple> + </term> + <term name="folio" form="short"> + <single>fol.</single> + <multiple>fols.</multiple> + </term> + <term name="issue" form="short"> + <single>no.</single> + <multiple>nos.</multiple> + </term> + <term name="line" form="short"> + <single>l.</single> + <multiple>ll.</multiple> + </term> + <term name="note" form="short"> + <single>n.</single> + <multiple>nn.</multiple> + </term> + <term name="opus" form="short"> + <single>op.</single> + <multiple>opp.</multiple> + </term> + <term name="page" form="short"> + <single>p.</single> + <multiple>pp.</multiple> + </term> + <term name="number-of-pages" form="short"> + <single>p.</single> + <multiple>pp.</multiple> + </term> + <term name="paragraph" form="short"> + <single>para.</single> + <multiple>paras.</multiple> + </term> + <term name="part" form="short"> + <single>pt.</single> + <multiple>pts.</multiple> + </term> + <term name="section" form="short"> + <single>sec.</single> + <multiple>secs.</multiple> + </term> + <term name="sub verbo" form="short"> + <single>s.v.</single> + <multiple>s.vv.</multiple> + </term> + <term name="verse" form="short"> + <single>v.</single> + <multiple>vv.</multiple> + </term> + <term name="volume" form="short"> + <single>vol.</single> + <multiple>vols.</multiple> + </term> + + <!-- SYMBOL LOCATOR FORMS --> + <term name="paragraph" form="symbol"> + <single>¶</single> + <multiple>¶¶</multiple> + </term> + <term name="section" form="symbol"> + <single>§</single> + <multiple>§§</multiple> + </term> + + <!-- LONG ROLE FORMS --> + <term name="director"> + <single>director</single> + <multiple>directors</multiple> + </term> + <term name="editor"> + <single>editor</single> + <multiple>editors</multiple> + </term> + <term name="editorial-director"> + <single>editor</single> + <multiple>editors</multiple> + </term> + <term name="illustrator"> + <single>illustrator</single> + <multiple>illustrators</multiple> + </term> + <term name="translator"> + <single>translator</single> + <multiple>translators</multiple> + </term> + <term name="editortranslator"> + <single>editor & translator</single> + <multiple>editors & translators</multiple> + </term> + + <!-- SHORT ROLE FORMS --> + <term name="director" form="short"> + <single>dir.</single> + <multiple>dirs.</multiple> + </term> + <term name="editor" form="short"> + <single>ed.</single> + <multiple>eds.</multiple> + </term> + <term name="editorial-director" form="short"> + <single>ed.</single> + <multiple>eds.</multiple> + </term> + <term name="illustrator" form="short"> + <single>ill.</single> + <multiple>ills.</multiple> + </term> + <term name="translator" form="short"> + <single>tran.</single> + <multiple>trans.</multiple> + </term> + <term name="editortranslator" form="short"> + <single>ed. & tran.</single> + <multiple>eds. & trans.</multiple> + </term> + + <!-- VERB ROLE FORMS --> + <term name="container-author" form="verb">by</term> + <term name="director" form="verb">directed by</term> + <term name="editor" form="verb">edited by</term> + <term name="editorial-director" form="verb">edited by</term> + <term name="illustrator" form="verb">illustrated by</term> + <term name="interviewer" form="verb">interview by</term> + <term name="recipient" form="verb">to</term> + <term name="reviewed-author" form="verb">by</term> + <term name="translator" form="verb">translated by</term> + <term name="editortranslator" form="verb">edited & translated by</term> + + <!-- SHORT VERB ROLE FORMS --> + <term name="director" form="verb-short">dir. by</term> + <term name="editor" form="verb-short">ed. by</term> + <term name="editorial-director" form="verb-short">ed. by</term> + <term name="illustrator" form="verb-short">illus. by</term> + <term name="translator" form="verb-short">trans. by</term> + <term name="editortranslator" form="verb-short">ed. & trans. by</term> + + <!-- LONG MONTH FORMS --> + <term name="month-01">January</term> + <term name="month-02">February</term> + <term name="month-03">March</term> + <term name="month-04">April</term> + <term name="month-05">May</term> + <term name="month-06">June</term> + <term name="month-07">July</term> + <term name="month-08">August</term> + <term name="month-09">September</term> + <term name="month-10">October</term> + <term name="month-11">November</term> + <term name="month-12">December</term> + + <!-- SHORT MONTH FORMS --> + <term name="month-01" form="short">Jan.</term> + <term name="month-02" form="short">Feb.</term> + <term name="month-03" form="short">Mar.</term> + <term name="month-04" form="short">Apr.</term> + <term name="month-05" form="short">May</term> + <term name="month-06" form="short">Jun.</term> + <term name="month-07" form="short">Jul.</term> + <term name="month-08" form="short">Aug.</term> + <term name="month-09" form="short">Sep.</term> + <term name="month-10" form="short">Oct.</term> + <term name="month-11" form="short">Nov.</term> + <term name="month-12" form="short">Dec.</term> + + <!-- SEASONS --> + <term name="season-01">Spring</term> + <term name="season-02">Summer</term> + <term name="season-03">Autumn</term> + <term name="season-04">Winter</term> + </terms> +</locale> diff --git a/lisp/oc-csl.el b/lisp/oc-csl.el new file mode 100644 index 0000000..a7a2a60 --- /dev/null +++ b/lisp/oc-csl.el @@ -0,0 +1,603 @@ +;;; oc-csl.el --- csl citation processor for Org -*- lexical-binding: t; -*- + +;; Copyright (C) 2021 Free Software Foundation, Inc. + +;; Author: Nicolas Goaziou <mail@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 `csl' citation processor, which provides +;; the "export" capability for citations. + +;; The processor relies on the external Citeproc Emacs library, which must be +;; available prior to loading this library. + +;; By default, citations are rendered in Chicago author-date CSL style. You can +;; use another style file by specifying it in `org-cite-export-processors' or +;; from within the document by adding the file name to "cite_export" keyword +;; +;; #+cite_export: csl /path/to/style-file.csl +;; #+cite_export: csl "/path/to/style-file.csl" +;; +;; With the variable `org-cite-csl-styles-dir' set appropriately, the +;; above can even be shortened to +;; +;; #+cite_export: csl style-file.csl +;; +;; Styles can be downloaded, for instance, from the Zotero Style Repository +;; (<https://www.zotero.org/styles>). Dependent styles (which are not "unique" +;; in the Zotero Style Repository terminology) are not supported. + +;; The processor uses the "en-US" CSL locale file shipped with Org for rendering +;; localized dates and terms in the references, independently of the language +;; settings of the Org document. Additional CSL locales can be made available +;; by setting `org-cite-csl-locales-dir' to a directory containing the locale +;; files in question (see <https://github.com/citation-style-language/locales> +;; for such files). + +;; Bibliography is defined with the "bibliography" keyword. It supports files +;; with ".bib", ".bibtex", and ".json" extensions. References are exported using +;; the "print_bibliography" keyword. + +;; The library supports the following citation styles: +;; +;; - noauthor (na), including bare (b), caps (c) and bare-caps (bc) variants, +;; - default style, including bare (b), caps (c) and bare-caps (bc) variants. + +;; CSL styles recognize "locator" in citation references' suffix. For example, +;; in the citation +;; +;; [cite:see @Tarski-1965 chapter 1, for an example] +;; +;; "chapter 1" is the locator. The whole citation is rendered as +;; +;; (see Tarski 1965, chap. 1 for an example) +;; +;; in the default CSL style. +;; +;; The locator starts with a locator term, among "bk.", "bks.", "book", "chap.", +;; "chaps.", "chapter", "col.", "cols.", "column", "figure", "fig.", "figs.", +;; "folio", "fol.", "fols.", "number", "no.", "nos.", "line", "l.", "ll.", +;; "note", "n.", "nn.", "opus", "op.", "opp.", "page", "p.", "pp.", "paragraph", +;; "para.", "paras.", "¶", "¶¶", "§", "§§", "part", "pt.", "pts.", "section", +;; "sec.", "secs.", "sub verbo", "s.v.", "s.vv.", "verse", "v.", "vv.", +;; "volume", "vol.", and "vols.". It ends with the last comma or digit in the +;; suffix, whichever comes last, or runs till the end of the suffix. +;; +;; 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. + +;; This library was heavily inspired by and borrows from András Simonyi's +;; Citeproc Org (<https://github.com/andras-simonyi/citeproc-org>) library. +;; Many thanks to him! + +;;; Code: +(require 'bibtex) +(require 'json) +(require 'org-cite) + +(require 'citeproc nil t) +(declare-function citeproc-style-cite-note "ext:citeproc") +(declare-function citeproc-proc-style "ext:citeproc") +(declare-function citeproc-bt-entry-to-csl "ext:citeproc") +(declare-function citeproc-locale-getter-from-dir "ext:citeproc") +(declare-function citeproc-create "ext:citeproc") +(declare-function citeproc-citation-create "ext:citeproc") +(declare-function citeproc-append-citations "ext:citeproc") +(declare-function citeproc-render-citations "ext:citeproc") +(declare-function citeproc-render-bib "ext:citeproc") + +(declare-function org-element-interpret-data "org-element" (data)) +(declare-function org-element-map "org-element" (data types fun &optional info first-match no-recursion with-affiliated)) +(declare-function org-element-property "org-element" (property element)) +(declare-function org-element-put-property "org-element" (element property value)) + +(declare-function org-export-data "org-export" (data info)) +(declare-function org-export-derived-backend-p "org-export" (backend &rest backends)) +(declare-function org-export-get-footnote-number "org-export" (footnote info &optional data body-first)) + + +;;; Customization + +;;;; Location of CSL directories +(defcustom org-cite-csl-locales-dir nil + "Directory of CSL locale files. +If nil then only the fallback en-US locale will be available." + :group 'org-cite + :package-version '(Org . "9.5") + :type '(choice + (dir :tag "Locales directory") + (const :tag "Use en-US locale only" nil)) + :safe t) + +(defcustom org-cite-csl-styles-dir nil + "Directory of CSL style files. +When non-nil, relative style file names are expanded relatively to this +directory. This variable is ignored when style file is absolute." + :group 'org-cite + :package-version '(Org . "9.5") + :type '(choice + (dir :tag "Styles directory") + (const :tag "Use absolute file names" nil)) + :safe t) + +;;;; Citelinks +(defcustom org-cite-csl-link-cites t + "When non-nil, link cites to references." + :group 'org-cite + :package-version '(Org . "9.5") + :type 'boolean + :safe t) + +(defcustom org-cite-csl-no-citelinks-backends '(ascii) + "List of export back-ends for which cite linking is disabled. +Cite linking for export back-ends derived from any of the back-ends listed here, +is also disabled." + :group 'org-cite + :package-version '(Org . "9.5") + :type '(repeat symbol) + :safe t) + +;;;; Output-specific variables +(defcustom org-cite-csl-html-hanging-indent "1.5em" + "Size of hanging-indent for HTML output in valid CSS units." + :group 'org-cite + :package-version '(Org . "9.5") + :type 'string + :safe t) + +(defcustom org-cite-csl-html-label-width-per-char "0.6em" + "Character width in CSS units for calculating entry label widths. +Used only when `second-field-align' is activated by the used CSL style." + :group 'org-cite + :package-version '(Org . "9.5") + :type 'string + :safe t) + +(defcustom org-cite-csl-latex-hanging-indent "1.5em" + "Size of hanging-indent for LaTeX output in valid LaTeX units." + :group 'org-cite + :package-version '(Org . "9.5") + :type 'string + :safe t) + + +;;; Internal variables +(defconst org-cite-csl--etc-dir + (expand-file-name + (concat (file-name-directory (locate-library "oc")) + "../etc/csl/")) + "Directory \"etc/\" from repository.") + +(defconst org-cite-csl--fallback-locales-dir org-cite-csl--etc-dir + "Fallback CSL locale files directory.") + +(defconst org-cite-csl--fallback-style-file + (expand-file-name "chicago-author-date.csl" + org-cite-csl--etc-dir) + "Default CSL style file, or nil. +If nil then the Chicago author-date style is used as a fallback.") + +(defconst org-cite-csl--label-alist + '(("bk." . "book") + ("bks." . "book") + ("book" . "book") + ("chap." . "chapter") + ("chaps." . "chapter") + ("chapter" . "chapter") + ("col." . "column") + ("cols." . "column") + ("column" . "column") + ("figure" . "figure") + ("fig." . "figure") + ("figs." . "figure") + ("folio" . "folio") + ("fol." . "folio") + ("fols." . "folio") + ("number" . "number") + ("no." . "number") + ("nos." . "number") + ("line" . "line") + ("l." . "line") + ("ll." . "line") + ("note" . "note") + ("n." . "note") + ("nn." . "note") + ("opus" . "opus") + ("op." . "opus") + ("opp." . "opus") + ("page" . "page") + ("p" . "page") + ("p." . "page") + ("pp." . "page") + ("paragraph" . "paragraph") + ("para." . "paragraph") + ("paras." . "paragraph") + ("¶" . "paragraph") + ("¶¶" . "paragraph") + ("§" . "paragraph") + ("§§" . "paragraph") + ("part" . "part") + ("pt." . "part") + ("pts." . "part") + ("section" . "section") + ("sec." . "section") + ("secs." . "section") + ("sub verbo" . "sub verbo") + ("s.v." . "sub verbo") + ("s.vv." . "sub verbo") + ("verse" . "verse") + ("v." . "verse") + ("vv." . "verse") + ("volume" . "volume") + ("vol." . "volume") + ("vols." . "volume")) + "Alist mapping locator names to locators.") + +(defconst org-cite-csl--label-regexp + (rx word-start + (regexp (regexp-opt (mapcar #'car org-cite-csl--label-alist) t)) + (0+ digit) + (or word-start line-end (any ?\s ?\t))) + "Regexp matching a label in a citation reference suffix. +Label is in match group 1.") + + +;;; Internal functions +(defun org-cite-csl--barf-without-citeproc () + "Raise an error if Citeproc library is not loaded." + (unless (featurep 'citeproc) "Citeproc library is not loaded")) + +(defun org-cite-csl--note-style-p (info) + "Non-nil when bibliography style implies wrapping citations in footnotes. +INFO is the export state, as a property list." + (citeproc-style-cite-note + (citeproc-proc-style + (org-cite-csl--processor info)))) + +(defun org-cite-csl--no-affixes-p (citation info) + "Non-nil when CITATION should be exported without affix. +INFO is the export data, as a property list." + (pcase (org-cite-citation-style citation info) + (`(,(or "noauthor" "na" `nil) . ,(or "bare" "b" "bare-caps" "bc")) t) + (_ nil))) + +(defun org-cite-csl--capitalize-p (citation info) + "Non-nil when CITATION should be capitalized. +INFO is the export-data, as a property list." + (pcase (org-cite-citation-style citation info) + (`(,(or "noauthor" "na" `nil) . ,(or "caps" "c" "bare-caps" "bc")) t) + (_ nil))) + +(defun org-cite-csl--no-author-p (reference info) + "Non-nil when citation REFERENCE should be exported without author. +INFO is the export data, as a property list." + (pcase (org-cite-citation-style (org-element-property :parent reference) info) + (`(,(or "noauthor" "na") . ,_) t) + (_ nil))) + +(defun org-cite-csl--no-citelinks-p (info) + "Non-nil when export BACKEND should not create cite-reference links." + (or (not org-cite-csl-link-cites) + (and org-cite-csl-no-citelinks-backends + (apply #'org-export-derived-backend-p + (plist-get info :back-end) + org-cite-csl-no-citelinks-backends)) + ;; No references are being exported anyway. + (not (org-element-map (plist-get info :parse-tree) 'keyword + (lambda (k) + (equal "PRINT_BIBLIOGRAPHY" (org-element-property :key k))) + info t)))) + +(defun org-cite-csl--output-format (info) + "Return expected Citeproc's output format. +INFO is the export state, as a property list. The return value is a symbol +corresponding to one of the output formats supported by Citeproc: `html', +`latex', or `org'." + (let ((backend (plist-get info :back-end))) + (cond + ((org-export-derived-backend-p backend 'html) 'html) + ((org-export-derived-backend-p backend 'latex) 'latex) + (t 'org)))) + +(defun org-cite-csl--style-file (info) + "Return style file associated to current export process. + +INFO is the export state, as a property list. + +When file name is relative, expand it according to `org-cite-csl-styles-dir', +or raise an error if the variable is unset." + (pcase (org-cite-bibliography-style info) + ('nil org-cite-csl--fallback-style-file) + ((and (pred file-name-absolute-p) file) file) + ((and (guard org-cite-csl-styles-dir) file) + (expand-file-name file org-cite-csl-styles-dir)) + (other + (user-error "Cannot handle relative style file name" other)))) + +(defun org-cite-csl--itemgetter (bibliography) + "Return Citeproc's \"itemgetter\" function for BIBLIOGRAPHY files. +The function handles \".bib\", \".bibtex\" and \".json\" files." + (let ((cache (make-hash-table :test #'equal))) + (dolist (file bibliography) + (pcase (file-name-extension file) + ("json" + (let ((json-array-type 'list) + (json-key-type 'symbol)) + (dolist (item (json-read-file file)) + (puthash (cdr (assq 'id item)) item cache)))) + ((and (or "bib" "bibtex") ext) + (with-temp-buffer + (insert-file-contents file) + (goto-char (point-min)) + (bibtex-set-dialect (if (string= ext "bib") 'biblatex 'BibTeX) t) + (bibtex-map-entries + (lambda (key &rest _) + (puthash key + (citeproc-bt-entry-to-csl (bibtex-parse-entry)) + cache))))) + (ext + (user-error "Unknown bibliography extension: %S" ext)))) + (lambda (itemids) + (mapcar (lambda (id) + (cons id (gethash id cache))) + itemids)))) + +(defun org-cite-csl--locale-getter () + "Return a locale getter. +The getter looks for locales in `org-cite-csl-locales-dir' directory. If it +cannot find them, it retrieves the default \"en_US\" from +`org-cite-csl--fallback-locales-dir'." + (lambda (loc) + (or (and org-cite-csl-locales-dir + (ignore-errors + (funcall (citeproc-locale-getter-from-dir org-cite-csl-locales-dir) + loc))) + (funcall (citeproc-locale-getter-from-dir + org-cite-csl--fallback-locales-dir) + loc)))) + +(defun org-cite-csl--processor (info) + "Return Citeproc processor reading items from current bibliography. + +INFO is the export state, as a property list. + +Newly created processor is stored as the value of the `:cite-citeproc-processor' +property in INFO." + (or (plist-get info :cite-citeproc-processor) + (let* ((bibliography (plist-get info :bibliography)) + (locale (or (plist-get info :language) "en_US")) + (processor + (citeproc-create + (org-cite-csl--style-file info) + (org-cite-csl--itemgetter bibliography) + (org-cite-csl--locale-getter) + locale))) + (plist-put info :cite-citeproc-processor processor) + processor))) + +(defun org-cite-csl--parse-reference (reference info) + "Return Citeproc's structure associated to citation REFERENCE. + +INFO is the export state, as a property list. + +The result is a association list. Keys are: `id', `suppress-author', `prefix', +`suffix', `location', `locator' and `label'." + (let (label location-start locator-start location locator prefix suffix) + ;; Parse suffix. Insert it in a temporary buffer to find + ;; different parts: pre-label, label, locator, location (label + + ;; locator), and suffix. + (with-temp-buffer + (save-excursion + (insert (org-element-interpret-data + (org-element-property :suffix reference)))) + (cond + ((re-search-forward org-cite-csl--label-regexp nil t) + (setq location-start (match-beginning 0)) + (setq label (cdr (assoc (match-string 1) org-cite-csl--label-alist))) + (setq locator-start (match-end 1))) + ((re-search-forward (rx digit) nil t) + (setq location-start (match-beginning 0)) + (setq label "page") + (setq locator-start location-start)) + (t + (setq suffix (org-element-property :suffix reference)))) + ;; Find locator's end, and suffix, if any. To that effect, look + ;; for the last comma or digit after label, whichever comes + ;; last. + (unless suffix + (goto-char (point-max)) + (let ((re (rx (or "," (group digit))))) + (when (re-search-backward re location-start t) + (goto-char (or (match-end 1) (match-beginning 0))) + (setq location (buffer-substring location-start (point))) + (setq locator (org-trim (buffer-substring locator-start (point)))) + ;; Skip comma in suffix. + (setq suffix + (org-cite-parse-objects + (buffer-substring (match-end 0) (point-max)) + t))))) + (setq prefix + (org-cite-concat + (org-element-property :prefix reference) + (and location-start + (org-cite-parse-objects + (buffer-substring 1 location-start) + t))))) + ;; Return value. + (let ((export + (lambda (data) + (org-string-nw-p + (org-trim + ;; When Citeproc exports to Org syntax, avoid mix and + ;; matching output formats by also generating Org + ;; syntax for prefix and suffix. + (if (eq 'org (org-cite-csl--output-format info)) + (org-element-interpret-data data) + (org-export-data data info))))))) + `((id . ,(org-element-property :key reference)) + (prefix . ,(funcall export prefix)) + (suffix . ,(funcall export suffix)) + (locator . ,locator) + (label . ,label) + (location . ,location) + (suppress-author . ,(org-cite-csl--no-author-p reference info)))))) + +(defun org-cite-csl--create-structure (citation info) + "Create Citeproc structure for CITATION object. +INFO is the export state, as a property list." + (let* ((cites (mapcar (lambda (r) + (org-cite-csl--parse-reference r info)) + (org-cite-get-references citation))) + (footnote (org-cite-inside-footnote-p citation))) + ;; Global prefix is inserted in front of the prefix of the first + ;; reference. + (let ((global-prefix (org-element-property :prefix citation))) + (when global-prefix + (let* ((first (car cites)) + (prefix (org-element-property :prefix first))) + (org-element-put-property + first :prefix (org-cite-concat global-prefix prefix))))) + ;; Global suffix is appended to the suffix of the last reference. + (let ((global-suffix (org-element-property :suffix citation))) + (when global-suffix + (let* ((last (org-last cites)) + (suffix (org-element-property :suffix last))) + (org-element-put-property + last :suffix (org-cite-concat suffix global-suffix))))) + ;; Check if CITATION needs wrapping, i.e., it should be wrapped in + ;; a footnote, but isn't yet. + (when (and (not footnote) (org-cite-csl--note-style-p info)) + (org-cite-adjust-note citation info) + (org-cite-wrap-citation citation info)) + ;; Return structure. + (citeproc-citation-create + :note-index (and footnote (org-export-get-footnote-number footnote info)) + :cites cites + :capitalize-first (or footnote (org-cite-csl--capitalize-p citation info)) + :suppress-affixes (org-cite-csl--no-affixes-p citation info)))) + +(defun org-cite-csl--rendered-citations (info) + "Return the rendered citations as an association list. + +INFO is the export state, as a property list. + +Return an alist (CITATION . OUTPUT) where CITATION object has been rendered as +OUTPUT using Citeproc." + (or (plist-get info :cite-citeproc-rendered-citations) + (let* ((citations (org-cite-list-citations info)) + (processor (org-cite-csl--processor info)) + (structures + (mapcar (lambda (c) (org-cite-csl--create-structure c info)) + citations))) + (citeproc-append-citations structures processor) + (let* ((rendered + (citeproc-render-citations + processor + (org-cite-csl--output-format info) + (org-cite-csl--no-citelinks-p info))) + (result (seq-mapn #'cons citations rendered))) + (plist-put info :cite-citeproc-rendered-citations result) + result)))) + + +;;; Export capability +(defun org-cite-csl-render-citation (citation _style _backend info) + "Export CITATION object. +INFO is the export state, as a property list." + (org-cite-csl--barf-without-citeproc) + (let ((output (cdr (assq citation (org-cite-csl--rendered-citations info))))) + (if (not (eq 'org (org-cite-csl--output-format info))) + output + ;; Parse Org output to re-export it during the regular export + ;; process. + (org-cite-parse-objects output)))) + +(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 format + ('html + (concat + (and (cdr (assq 'second-field-align parameters)) + (let* ((max-offset (cdr (assq 'max-offset parameters))) + (char-width + (string-to-number org-cite-csl-html-label-width-per-char)) + (char-width-unit + (progn + (string-match (number-to-string char-width) + org-cite-csl-html-label-width-per-char) + (substring org-cite-csl-html-label-width-per-char + (match-end 0))))) + (format + "<style>.csl-left-margin{float: left; padding-right: 0em;} + .csl-right-inline{margin: 0 0 0 %d%s;}</style>" + (* max-offset char-width) + char-width-unit))) + (and (cdr (assq 'hanging-indent parameters)) + (format + "<style>.csl-entry{text-indent: -%s; margin-left: %s;}</style>" + org-cite-csl-html-hanging-indent + org-cite-csl-html-hanging-indent)) + output)) + ('latex + (if (cdr (assq 'hanging-indent parameters)) + (format "\\begin{hangparas}{%s}{1}\n%s\n\\end{hangparas}" + org-cite-csl-latex-hanging-indent + output) + output)) + (_ + ;; Parse Org output to re-export it during the regular export + ;; process. + (org-cite-parse-elements output))))) + +(defun org-cite-csl-finalizer (output _keys _files _style _backend info) + "Add \"hanging\" package if missing from LaTeX output. +OUTPUT is the export document, as a string. INFO is the export state, as a +property list." + (org-cite-csl--barf-without-citeproc) + (if (not (eq 'latex (org-cite-csl--output-format info))) + output + (with-temp-buffer + (save-excursion (insert output)) + (when (search-forward "\\begin{document}" nil t) + ;; Ensure there is a \usepackage{hanging} somewhere or add one. + (goto-char (match-beginning 0)) + (let ((re (rx "\\usepackage" (opt "[" (*? nonl) "]") "{hanging}"))) + (unless (re-search-backward re nil t) + (insert "\\usepackage{hanging}\n")))) + (buffer-string)))) + + +;;; Register `csl' processor +(org-cite-register-processor 'csl + :export-citation #'org-cite-csl-render-citation + :export-bibliography #'org-cite-csl-render-bibliography + :export-finalizer #'org-cite-csl-finalizer + :cite-styles + '((("noauthor" "na") ("bare" "b") ("bare-caps" "bc") ("caps" "c")) + (("nil") ("bare" "b") ("bare-caps" "bc") ("caps" "c")))) + +(provide 'org-cite-csl) +(provide 'oc-csl) +;;; oc-citeproc.el ends here |