summaryrefslogtreecommitdiff
path: root/support/texlab/src/citeproc
diff options
context:
space:
mode:
Diffstat (limited to 'support/texlab/src/citeproc')
-rw-r--r--support/texlab/src/citeproc/apa.csl1526
-rw-r--r--support/texlab/src/citeproc/mod.rs69
-rw-r--r--support/texlab/src/citeproc/name/mod.rs275
-rw-r--r--support/texlab/src/citeproc/name/parser.lalrpop152
-rw-r--r--support/texlab/src/citeproc/ris.rs466
5 files changed, 2488 insertions, 0 deletions
diff --git a/support/texlab/src/citeproc/apa.csl b/support/texlab/src/citeproc/apa.csl
new file mode 100644
index 0000000000..8454246a98
--- /dev/null
+++ b/support/texlab/src/citeproc/apa.csl
@@ -0,0 +1,1526 @@
+<?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="never" page-range-format="expanded">
+ <info>
+ <title>American Psychological Association 6th edition</title>
+ <title-short>APA</title-short>
+ <id>http://www.zotero.org/styles/apa</id>
+ <link href="http://www.zotero.org/styles/apa" rel="self"/>
+ <link href="http://owl.english.purdue.edu/owl/resource/560/01/" rel="documentation"/>
+ <author>
+ <name>Simon Kornblith</name>
+ <email>simon@simonster.com</email>
+ </author>
+ <author>
+ <name> Brenton M. Wiernik</name>
+ <email>zotero@wiernik.org</email>
+ </author>
+ <contributor>
+ <name>Bruce D'Arcus</name>
+ </contributor>
+ <contributor>
+ <name>Curtis M. Humphrey</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>Sebastian Karcher</name>
+ </contributor>
+ <category citation-format="author-date"/>
+ <category field="psychology"/>
+ <category field="generic-base"/>
+ <updated>2016-09-28T13:09:49+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="editortranslator" form="short">
+ <single>ed. &amp; trans.</single>
+ <multiple>eds. &amp; trans.</multiple>
+ </term>
+ <term name="translator" form="short">trans.</term>
+ <term name="interviewer" form="short">interviewer</term>
+ <term name="circa" form="short">ca.</term>
+ <term name="collection-editor" form="short">series ed.</term>
+ </terms>
+ </locale>
+ <locale xml:lang="es">
+ <terms>
+ <term name="from">de</term>
+ </terms>
+ </locale>
+ <locale xml:lang="de">
+ <terms>
+ <term name="et-al">et al.</term>
+ </terms>
+ </locale>
+ <locale xml:lang="da">
+ <terms>
+ <term name="et-al">et al.</term>
+ </terms>
+ </locale>
+ <locale xml:lang="nn">
+ <terms>
+ <term name="et-al">et al.</term>
+ </terms>
+ </locale>
+ <locale xml:lang="nb">
+ <terms>
+ <term name="et-al">et al.</term>
+ </terms>
+ </locale>
+ <macro name="container-contributors-booklike">
+ <choose>
+ <if variable="container-title">
+ <names variable="editor translator" delimiter=", &amp; ">
+ <name and="symbol" initialize-with=". " delimiter=", "/>
+ <label form="short" prefix=" (" text-case="title" suffix=")"/>
+ <substitute>
+ <names variable="editorial-director"/>
+ <names variable="collection-editor"/>
+ <names variable="container-author"/>
+ </substitute>
+ </names>
+ </if>
+ </choose>
+ </macro>
+ <macro name="container-contributors">
+ <choose>
+ <!-- book is here to catch software with container titles -->
+ <if type="book broadcast chapter entry entry-dictionary entry-encyclopedia graphic map personal_communication report speech" match="any">
+ <text macro="container-contributors-booklike"/>
+ </if>
+ <else-if type="paper-conference">
+ <choose>
+ <if variable="collection-editor container-author editor" match="any">
+ <text macro="container-contributors-booklike"/>
+ </if>
+ </choose>
+ </else-if>
+ </choose>
+ </macro>
+ <macro name="secondary-contributors-booklike">
+ <group delimiter="; ">
+ <choose>
+ <if variable="title">
+ <names variable="interviewer">
+ <name and="symbol" initialize-with=". " delimiter=", "/>
+ <label form="short" prefix=", " text-case="title"/>
+ </names>
+ </if>
+ </choose>
+ <choose>
+ <if variable="container-title" match="none">
+ <group delimiter="; ">
+ <names variable="container-author">
+ <label form="verb-short" suffix=" " text-case="title"/>
+ <name and="symbol" initialize-with=". " delimiter=", "/>
+ </names>
+ <names variable="editor translator" delimiter="; ">
+ <name and="symbol" initialize-with=". " delimiter=", "/>
+ <label form="short" prefix=", " text-case="title"/>
+ </names>
+ </group>
+ </if>
+ </choose>
+ </group>
+ </macro>
+ <macro name="secondary-contributors">
+ <choose>
+ <!-- book is here to catch software with container titles -->
+ <if type="book broadcast chapter entry entry-dictionary entry-encyclopedia graphic map report" match="any">
+ <text macro="secondary-contributors-booklike"/>
+ </if>
+ <else-if type="personal_communication">
+ <group delimiter="; ">
+ <group delimiter=" ">
+ <choose>
+ <if variable="genre" match="any">
+ <text variable="genre" text-case="capitalize-first"/>
+ </if>
+ <else>
+ <text term="letter" text-case="capitalize-first"/>
+ </else>
+ </choose>
+ <names variable="recipient" delimiter=", ">
+ <label form="verb" suffix=" "/>
+ <name and="symbol" delimiter=", "/>
+ </names>
+ </group>
+ <text variable="medium" text-case="capitalize-first"/>
+ <choose>
+ <if variable="container-title" match="none">
+ <names variable="editor translator" delimiter="; ">
+ <name and="symbol" initialize-with=". " delimiter=", "/>
+ <label form="short" prefix=", " text-case="title"/>
+ </names>
+ </if>
+ </choose>
+ </group>
+ </else-if>
+ <else-if type="song">
+ <choose>
+ <if variable="original-author composer" match="any">
+ <group delimiter="; ">
+ <!-- Replace prefix with performer label as that becomes available -->
+ <names variable="author" prefix="Recorded by ">
+ <label form="verb" text-case="title"/>
+ <name and="symbol" initialize-with=". " delimiter=", "/>
+ </names>
+ <names variable="translator">
+ <name and="symbol" initialize-with=". " delimiter=", "/>
+ <label form="short" prefix=", " text-case="title"/>
+ </names>
+ </group>
+ </if>
+ </choose>
+ </else-if>
+ <else-if type="article-journal article-magazine article-newspaper" match="any">
+ <group delimiter="; ">
+ <choose>
+ <if variable="title">
+ <names variable="interviewer" delimiter="; ">
+ <name and="symbol" initialize-with=". " delimiter=", "/>
+ <label form="short" prefix=", " text-case="title"/>
+ </names>
+ </if>
+ </choose>
+ <names variable="translator" delimiter="; ">
+ <name and="symbol" initialize-with=". " delimiter=", "/>
+ <label form="short" prefix=", " text-case="title"/>
+ </names>
+ </group>
+ </else-if>
+ <else-if type="paper-conference">
+ <choose>
+ <if variable="collection-editor editor" match="any">
+ <text macro="secondary-contributors-booklike"/>
+ </if>
+ <else>
+ <group delimiter="; ">
+ <choose>
+ <if variable="title">
+ <names variable="interviewer" delimiter="; ">
+ <name and="symbol" initialize-with=". " delimiter=", "/>
+ <label form="short" prefix=", " text-case="title"/>
+ </names>
+ </if>
+ </choose>
+ <names variable="translator" delimiter="; ">
+ <name and="symbol" initialize-with=". " delimiter=", "/>
+ <label form="short" prefix=", " text-case="title"/>
+ </names>
+ </group>
+ </else>
+ </choose>
+ </else-if>
+ <else>
+ <group delimiter="; ">
+ <choose>
+ <if variable="title">
+ <names variable="interviewer">
+ <name and="symbol" initialize-with=". " delimiter="; "/>
+ <label form="short" prefix=", " text-case="title"/>
+ </names>
+ </if>
+ </choose>
+ <names variable="editor translator" delimiter="; ">
+ <name and="symbol" initialize-with=". " delimiter=", "/>
+ <label form="short" prefix=", " text-case="title"/>
+ </names>
+ </group>
+ </else>
+ </choose>
+ </macro>
+ <macro name="author">
+ <choose>
+ <if type="song">
+ <names variable="composer" delimiter=", ">
+ <name name-as-sort-order="all" and="symbol" sort-separator=", " initialize-with=". " delimiter=", " delimiter-precedes-last="always"/>
+ <substitute>
+ <names variable="original-author"/>
+ <names variable="author"/>
+ <names variable="translator">
+ <name name-as-sort-order="all" and="symbol" sort-separator=", " initialize-with=". " delimiter=", " delimiter-precedes-last="always"/>
+ <label form="short" prefix=" (" suffix=")" text-case="title"/>
+ </names>
+ <group delimiter=" ">
+ <text macro="title"/>
+ <text macro="description"/>
+ <text macro="format"/>
+ </group>
+ </substitute>
+ </names>
+ </if>
+ <else-if type="treaty"/>
+ <else>
+ <names variable="author" delimiter=", ">
+ <name name-as-sort-order="all" and="symbol" sort-separator=", " initialize-with=". " delimiter=", " delimiter-precedes-last="always"/>
+ <substitute>
+ <names variable="illustrator"/>
+ <names variable="composer"/>
+ <names variable="director">
+ <name name-as-sort-order="all" and="symbol" sort-separator=", " initialize-with=". " delimiter=", " delimiter-precedes-last="always"/>
+ <label form="long" prefix=" (" suffix=")" text-case="title"/>
+ </names>
+ <choose>
+ <if variable="container-title">
+ <choose>
+ <if type="book entry entry-dictionary entry-encyclopedia">
+ <text macro="title"/>
+ </if>
+ <else>
+ <names variable="translator"/>
+ </else>
+ </choose>
+ <names variable="translator">
+ <name name-as-sort-order="all" and="symbol" sort-separator=", " initialize-with=". " delimiter=", " delimiter-precedes-last="always"/>
+ <label form="short" prefix=" (" suffix=")" text-case="title"/>
+ </names>
+ </if>
+ </choose>
+ <names variable="editor translator" delimiter=", ">
+ <name name-as-sort-order="all" and="symbol" sort-separator=", " initialize-with=". " delimiter=", " delimiter-precedes-last="always"/>
+ <label form="short" prefix=" (" suffix=")" text-case="title"/>
+ </names>
+ <names variable="editorial-director">
+ <name name-as-sort-order="all" and="symbol" sort-separator=", " initialize-with=". " delimiter=", " delimiter-precedes-last="always"/>
+ <label form="short" prefix=" (" suffix=")" text-case="title"/>
+ </names>
+ <names variable="collection-editor">
+ <name name-as-sort-order="all" and="symbol" sort-separator=", " initialize-with=". " delimiter=", " delimiter-precedes-last="always"/>
+ <label form="short" prefix=" (" suffix=")" text-case="title"/>
+ </names>
+ <choose>
+ <if type="report">
+ <text variable="publisher"/>
+ </if>
+ </choose>
+ <group delimiter=" ">
+ <text macro="title"/>
+ <text macro="description"/>
+ <text macro="format"/>
+ </group>
+ </substitute>
+ </names>
+ </else>
+ </choose>
+ </macro>
+ <macro name="author-short">
+ <choose>
+ <if type="patent" variable="number" match="all">
+ <text macro="patent-number"/>
+ </if>
+ <else-if type="treaty">
+ <text variable="title" form="short"/>
+ </else-if>
+ <else-if type="personal_communication">
+ <choose>
+ <if variable="archive DOI publisher URL" match="none">
+ <group delimiter=", ">
+ <names variable="author">
+ <name and="symbol" delimiter=", " initialize-with=". "/>
+ <substitute>
+ <text variable="title" form="short" quotes="true"/>
+ </substitute>
+ </names>
+ <!-- This should be localized -->
+ <text value="personal communication"/>
+ </group>
+ </if>
+ <else>
+ <names variable="author" delimiter=", ">
+ <name form="short" and="symbol" delimiter=", " initialize-with=". "/>
+ <substitute>
+ <names variable="editor"/>
+ <names variable="translator"/>
+ <choose>
+ <if variable="container-title">
+ <text variable="title" form="short" quotes="true"/>
+ </if>
+ <else>
+ <text variable="title" form="short" font-style="italic"/>
+ </else>
+ </choose>
+ <text macro="format-short" prefix="[" suffix="]"/>
+ </substitute>
+ </names>
+ </else>
+ </choose>
+ </else-if>
+ <else-if type="song">
+ <names variable="composer" delimiter=", ">
+ <name form="short" and="symbol" delimiter=", " initialize-with=". "/>
+ <substitute>
+ <names variable="original-author"/>
+ <names variable="author"/>
+ <names variable="translator"/>
+ <choose>
+ <if variable="container-title">
+ <text variable="title" form="short" quotes="true"/>
+ </if>
+ <else>
+ <text variable="title" form="short" font-style="italic"/>
+ </else>
+ </choose>
+ <text macro="format-short" prefix="[" suffix="]"/>
+ </substitute>
+ </names>
+ </else-if>
+ <else>
+ <names variable="author" delimiter=", ">
+ <name form="short" and="symbol" delimiter=", " initialize-with=". "/>
+ <substitute>
+ <names variable="illustrator"/>
+ <names variable="composer"/>
+ <names variable="director"/>
+ <choose>
+ <if variable="container-title">
+ <choose>
+ <if type="book entry entry-dictionary entry-encyclopedia">
+ <text variable="title" form="short" quotes="true"/>
+ </if>
+ <else>
+ <names variable="translator"/>
+ </else>
+ </choose>
+ </if>
+ </choose>
+ <names variable="editor"/>
+ <names variable="editorial-director"/>
+ <names variable="translator"/>
+ <choose>
+ <if type="report" variable="publisher" match="all">
+ <text variable="publisher"/>
+ </if>
+ <else-if type="legal_case">
+ <text variable="title" font-style="italic"/>
+ </else-if>
+ <else-if type="bill legislation" match="any">
+ <text variable="title" form="short"/>
+ </else-if>
+ <else-if variable="reviewed-author" type="review review-book" match="any">
+ <text macro="format-short" prefix="[" suffix="]"/>
+ </else-if>
+ <else-if type="post post-weblog webpage" variable="container-title" match="any">
+ <text variable="title" form="short" quotes="true"/>
+ </else-if>
+ <else>
+ <text variable="title" form="short" font-style="italic"/>
+ </else>
+ </choose>
+ <text macro="format-short" prefix="[" suffix="]"/>
+ </substitute>
+ </names>
+ </else>
+ </choose>
+ </macro>
+ <macro name="patent-number">
+ <!-- authority: U.S. ; genre: patent ; number: 123,445 -->
+ <group delimiter=" ">
+ <text variable="authority"/>
+ <choose>
+ <if variable="genre">
+ <text variable="genre" text-case="capitalize-first"/>
+ </if>
+ <else>
+ <!-- This should be localized -->
+ <text value="patent" text-case="capitalize-first"/>
+ </else>
+ </choose>
+ <group delimiter=" ">
+ <text term="issue" form="short" text-case="capitalize-first"/>
+ <text variable="number"/>
+ </group>
+ </group>
+ </macro>
+ <macro name="access">
+ <choose>
+ <if type="bill legal_case legislation" match="any"/>
+ <else-if variable="DOI" match="any">
+ <text variable="DOI" prefix="https://doi.org/"/>
+ </else-if>
+ <else-if variable="URL">
+ <group delimiter=" ">
+ <text term="retrieved" text-case="capitalize-first"/>
+ <choose>
+ <if type="post post-weblog webpage" match="any">
+ <date variable="accessed" form="text" suffix=","/>
+ </if>
+ </choose>
+ <text term="from"/>
+ <choose>
+ <if type="report">
+ <choose>
+ <if variable="author editor translator" match="any">
+ <!-- This should be localized -->
+ <text variable="publisher" suffix=" website:"/>
+ </if>
+ </choose>
+ </if>
+ <else-if type="post post-weblog webpage" match="any">
+ <!-- This should be localized -->
+ <text variable="container-title" suffix=" website:"/>
+ </else-if>
+ </choose>
+ <text variable="URL"/>
+ </group>
+ </else-if>
+ <else-if variable="archive">
+ <choose>
+ <if type="article article-journal article-magazine article-newspaper dataset paper-conference report speech thesis" match="any">
+ <!-- This section is for electronic database locations. Physical archives for these and other item types are called in 'publisher' macro -->
+ <choose>
+ <if variable="archive-place" match="none">
+ <group delimiter=" ">
+ <text term="retrieved" text-case="capitalize-first"/>
+ <text term="from"/>
+ <text variable="archive" suffix="."/>
+ <text variable="archive_location" prefix="(" suffix=")"/>
+ </group>
+ </if>
+ <else>
+ <text macro="publisher" suffix="."/>
+ </else>
+ </choose>
+ </if>
+ <else>
+ <text macro="publisher" suffix="."/>
+ </else>
+ </choose>
+ </else-if>
+ <else>
+ <text macro="publisher" suffix="."/>
+ </else>
+ </choose>
+ </macro>
+ <macro name="title">
+ <choose>
+ <if type="treaty">
+ <group delimiter=", ">
+ <text variable="title" text-case="title"/>
+ <names variable="author">
+ <name initialize-with="." form="short" delimiter="-"/>
+ </names>
+ </group>
+ </if>
+ <else-if type="patent" variable="number" match="all">
+ <text macro="patent-number" font-style="italic"/>
+ </else-if>
+ <else-if variable="title">
+ <choose>
+ <if variable="version" type="book" match="all">
+ <!---This is a hack until we have a software type -->
+ <text variable="title"/>
+ </if>
+ <else-if variable="reviewed-author reviewed-title" type="review review-book" match="any">
+ <choose>
+ <if variable="reviewed-title">
+ <choose>
+ <if type="post post-weblog webpage" variable="container-title" match="any">
+ <text variable="title"/>
+ </if>
+ <else>
+ <text variable="title" font-style="italic"/>
+ </else>
+ </choose>
+ </if>
+ </choose>
+ </else-if>
+ <else-if type="post post-weblog webpage" variable="container-title" match="any">
+ <text variable="title"/>
+ </else-if>
+ <else>
+ <text variable="title" font-style="italic"/>
+ </else>
+ </choose>
+ </else-if>
+ <else-if variable="interviewer" type="interview" match="any">
+ <names variable="interviewer">
+ <label form="verb-short" suffix=" " text-case="capitalize-first"/>
+ <name and="symbol" initialize-with=". " delimiter=", "/>
+ </names>
+ </else-if>
+ </choose>
+ </macro>
+ <!-- APA has four descriptive sections following the title: -->
+ <!-- (description), [format], container, event -->
+ <macro name="description">
+ <group prefix="(" suffix=")">
+ <choose>
+ <!-- book is here to catch software with container titles -->
+ <if type="book report" match="any">
+ <choose>
+ <if variable="container-title">
+ <text macro="secondary-contributors"/>
+ </if>
+ <else>
+ <group delimiter="; ">
+ <text macro="description-report"/>
+ <text macro="secondary-contributors"/>
+ </group>
+ </else>
+ </choose>
+ </if>
+ <else-if type="thesis">
+ <group delimiter="; ">
+ <group delimiter=", ">
+ <text variable="genre" text-case="capitalize-first"/>
+ <choose>
+ <!-- In APA journals, the university of a thesis is always cited, even if another locator is given -->
+ <if variable="DOI URL archive" match="any">
+ <text variable="publisher"/>
+ </if>
+ </choose>
+ </group>
+ <text macro="locators"/>
+ <text macro="secondary-contributors"/>
+ </group>
+ </else-if>
+ <else-if type="book interview manuscript motion_picture musical_score pamphlet post-weblog speech webpage" match="any">
+ <group delimiter="; ">
+ <text macro="locators"/>
+ <text macro="secondary-contributors"/>
+ </group>
+ </else-if>
+ <else-if type="song">
+ <choose>
+ <if variable="container-title" match="none">
+ <text macro="locators"/>
+ </if>
+ </choose>
+ </else-if>
+ <else-if type="article dataset figure" match="any">
+ <choose>
+ <if variable="container-title">
+ <text macro="secondary-contributors"/>
+ </if>
+ <else>
+ <group delimiter="; ">
+ <text macro="locators"/>
+ <text macro="secondary-contributors"/>
+ </group>
+ </else>
+ </choose>
+ </else-if>
+ <else-if type="bill legislation legal_case patent treaty personal_communication" match="none">
+ <text macro="secondary-contributors"/>
+ </else-if>
+ </choose>
+ </group>
+ </macro>
+ <macro name="format">
+ <group prefix="[" suffix="]">
+ <choose>
+ <if variable="reviewed-author reviewed-title" type="review review-book" match="any">
+ <group delimiter=", ">
+ <choose>
+ <if variable="genre">
+ <!-- Delimiting by , rather than "of" to avoid incorrect grammar -->
+ <group delimiter=", ">
+ <text variable="genre" text-case="capitalize-first"/>
+ <choose>
+ <if variable="reviewed-title">
+ <text variable="reviewed-title" font-style="italic"/>
+ </if>
+ <else>
+ <!-- Assume `title` is title of reviewed work -->
+ <text variable="title" font-style="italic"/>
+ </else>
+ </choose>
+ </group>
+ </if>
+ <else>
+ <!-- This should be localized -->
+ <group delimiter=" ">
+ <text value="Review of"/>
+ <choose>
+ <if variable="reviewed-title">
+ <text variable="reviewed-title" font-style="italic"/>
+ </if>
+ <else>
+ <!-- Assume `title` is title of reviewed work -->
+ <text variable="title" font-style="italic"/>
+ </else>
+ </choose>
+ </group>
+ </else>
+ </choose>
+ <names variable="reviewed-author">
+ <label form="verb-short" suffix=" "/>
+ <name and="symbol" initialize-with=". " delimiter=", "/>
+ </names>
+ </group>
+ </if>
+ <else>
+ <text macro="format-short"/>
+ </else>
+ </choose>
+ </group>
+ </macro>
+ <macro name="format-short">
+ <choose>
+ <if variable="reviewed-author reviewed-title" type="review review-book" match="any">
+ <choose>
+ <if variable="reviewed-title" match="none">
+ <choose>
+ <if variable="genre">
+ <!-- Delimiting by , rather than "of" to avoid incorrect grammar -->
+ <group delimiter=", ">
+ <text variable="genre" text-case="capitalize-first"/>
+ <text variable="title" form="short" font-style="italic"/>
+ </group>
+ </if>
+ <else>
+ <!-- This should be localized -->
+ <group delimiter=" ">
+ <text value="Review of"/>
+ <text variable="title" form="short" font-style="italic"/>
+ </group>
+ </else>
+ </choose>
+ </if>
+ <else>
+ <text variable="title" form="short" quotes="true"/>
+ </else>
+ </choose>
+ </if>
+ <else-if type="speech thesis" match="any">
+ <text variable="medium" text-case="capitalize-first"/>
+ </else-if>
+ <!-- book is here to catch software with container titles -->
+ <else-if type="book report" match="any">
+ <choose>
+ <if variable="container-title" match="none">
+ <text macro="format-report"/>
+ </if>
+ </choose>
+ </else-if>
+ <else-if type="manuscript pamphlet" match="any">
+ <text variable="medium" text-case="capitalize-first"/>
+ </else-if>
+ <else-if type="personal_communication">
+ <text macro="secondary-contributors"/>
+ </else-if>
+ <else-if type="song">
+ <group delimiter="; ">
+ <text macro="secondary-contributors"/>
+ <choose>
+ <if variable="container-title" match="none">
+ <group delimiter=", ">
+ <text variable="genre" text-case="capitalize-first"/>
+ <text variable="medium" text-case="capitalize-first"/>
+ </group>
+ </if>
+ </choose>
+ </group>
+ </else-if>
+ <else-if type="paper-conference">
+ <group delimiter=", ">
+ <choose>
+ <if variable="collection-editor editor issue page volume" match="any">
+ <text variable="genre" text-case="capitalize-first"/>
+ </if>
+ </choose>
+ <text variable="medium" text-case="capitalize-first"/>
+ </group>
+ </else-if>
+ <else-if type="bill legislation legal_case patent treaty" match="none">
+ <choose>
+ <if variable="genre medium" match="any">
+ <group delimiter=", ">
+ <text variable="genre" text-case="capitalize-first"/>
+ <text variable="medium" text-case="capitalize-first"/>
+ </group>
+ </if>
+ <else-if type="dataset">
+ <!-- This should be localized -->
+ <text value="Data set"/>
+ </else-if>
+ </choose>
+ </else-if>
+ </choose>
+ </macro>
+ <macro name="description-report">
+ <choose>
+ <if variable="number">
+ <group delimiter="; ">
+ <group delimiter=" ">
+ <text variable="genre" text-case="title"/>
+ <!-- Replace with term="number" if that becomes available -->
+ <text term="issue" form="short" text-case="capitalize-first"/>
+ <text variable="number"/>
+ </group>
+ <text macro="locators"/>
+ </group>
+ </if>
+ <else>
+ <text macro="locators"/>
+ </else>
+ </choose>
+ </macro>
+ <macro name="format-report">
+ <choose>
+ <if variable="number">
+ <text variable="medium" text-case="capitalize-first"/>
+ </if>
+ <else>
+ <group delimiter=", ">
+ <text variable="genre" text-case="capitalize-first"/>
+ <text variable="medium" text-case="capitalize-first"/>
+ </group>
+ </else>
+ </choose>
+ </macro>
+ <macro name="archive">
+ <group delimiter=". ">
+ <group delimiter=", ">
+ <choose>
+ <if type="manuscript">
+ <text variable="genre"/>
+ </if>
+ </choose>
+ <group delimiter=" ">
+ <!-- Replace "archive" with "archive_collection" as that becomes available -->
+ <text variable="archive"/>
+ <text variable="archive_location" prefix="(" suffix=")"/>
+ </group>
+ </group>
+ <group delimiter=", ">
+ <!-- Move "archive" here when "archive_collection" becomes available -->
+ <text variable="archive-place"/>
+ </group>
+ </group>
+ </macro>
+ <macro name="publisher">
+ <choose>
+ <if type="manuscript pamphlet" match="any">
+ <choose>
+ <if variable="archive archive_location archive-place" match="any">
+ <group delimiter=". ">
+ <group delimiter=": ">
+ <text variable="publisher-place"/>
+ <text variable="publisher"/>
+ </group>
+ <text macro="archive"/>
+ </group>
+ </if>
+ <else>
+ <group delimiter=", ">
+ <text variable="genre"/>
+ <text variable="publisher"/>
+ <text variable="publisher-place"/>
+ </group>
+ </else>
+ </choose>
+ </if>
+ <else-if type="thesis" match="any">
+ <group delimiter=". ">
+ <group delimiter=", ">
+ <text variable="publisher"/>
+ <text variable="publisher-place"/>
+ </group>
+ <text macro="archive"/>
+ </group>
+ </else-if>
+ <else-if type="patent">
+ <group delimiter=". ">
+ <group delimiter=": ">
+ <text variable="publisher-place"/>
+ <text variable="publisher"/>
+ </group>
+ <text macro="archive"/>
+ </group>
+ </else-if>
+ <else-if type="article-journal article-magazine article-newspaper" match="any">
+ <text macro="archive"/>
+ </else-if>
+ <else-if type="post post-weblog webpage" match="none">
+ <group delimiter=". ">
+ <choose>
+ <if variable="event">
+ <choose>
+ <!-- Only print publisher info if published in a proceedings -->
+ <if variable="collection-editor editor issue page volume" match="any">
+ <group delimiter=": ">
+ <text variable="publisher-place"/>
+ <text variable="publisher"/>
+ </group>
+ </if>
+ </choose>
+ </if>
+ <else>
+ <group delimiter=": ">
+ <text variable="publisher-place"/>
+ <text variable="publisher"/>
+ </group>
+ </else>
+ </choose>
+ <text macro="archive"/>
+ </group>
+ </else-if>
+ </choose>
+ </macro>
+ <macro name="event">
+ <choose>
+ <if variable="event" type="speech paper-conference" match="any">
+ <choose>
+ <!-- Don't print event info if published in a proceedings -->
+ <if variable="collection-editor editor issue page volume" match="none">
+ <group delimiter=" ">
+ <text variable="genre" text-case="capitalize-first"/>
+ <group delimiter=" ">
+ <choose>
+ <if variable="genre">
+ <text term="presented at"/>
+ </if>
+ <else>
+ <text term="presented at" text-case="capitalize-first"/>
+ </else>
+ </choose>
+ <group delimiter=", ">
+ <text variable="event"/>
+ <text variable="event-place"/>
+ </group>
+ </group>
+ </group>
+ </if>
+ </choose>
+ </if>
+ </choose>
+ </macro>
+ <macro name="issued">
+ <choose>
+ <if type="bill legal_case legislation" match="any"/>
+ <else-if variable="issued">
+ <group>
+ <date variable="issued">
+ <date-part name="year"/>
+ </date>
+ <text variable="year-suffix"/>
+ <choose>
+ <if type="speech">
+ <date variable="issued" delimiter=" ">
+ <date-part prefix=", " name="month"/>
+ </date>
+ </if>
+ <else-if type="article article-magazine article-newspaper broadcast interview pamphlet personal_communication post post-weblog treaty webpage" match="any">
+ <date variable="issued">
+ <date-part prefix=", " name="month"/>
+ <date-part prefix=" " name="day"/>
+ </date>
+ </else-if>
+ <else-if type="paper-conference">
+ <choose>
+ <if variable="container-title" match="none">
+ <date variable="issued">
+ <date-part prefix=", " name="month"/>
+ <date-part prefix=" " name="day"/>
+ </date>
+ </if>
+ </choose>
+ </else-if>
+ <!-- Only year: article-journal chapter entry entry-dictionary entry-encyclopedia dataset figure graphic motion_picture manuscript map musical_score paper-conference [published] patent report review review-book song thesis -->
+ </choose>
+ </group>
+ </else-if>
+ <else-if variable="status">
+ <group>
+ <text variable="status" text-case="lowercase"/>
+ <text variable="year-suffix" prefix="-"/>
+ </group>
+ </else-if>
+ <else>
+ <group>
+ <text term="no date" form="short"/>
+ <text variable="year-suffix" prefix="-"/>
+ </group>
+ </else>
+ </choose>
+ </macro>
+ <macro name="issued-sort">
+ <choose>
+ <if type="article article-magazine article-newspaper broadcast interview pamphlet personal_communication post post-weblog speech treaty webpage" match="any">
+ <date variable="issued">
+ <date-part name="year"/>
+ <date-part name="month"/>
+ <date-part name="day"/>
+ </date>
+ </if>
+ <else>
+ <date variable="issued">
+ <date-part name="year"/>
+ </date>
+ </else>
+ </choose>
+ </macro>
+ <macro name="issued-year">
+ <group>
+ <choose>
+ <if type="personal_communication">
+ <choose>
+ <if variable="archive DOI publisher URL" match="none">
+ <!-- These variables indicate that the letter is retrievable by the reader. If not, then use the APA in-text-only personal communication format -->
+ <date variable="issued" form="text"/>
+ </if>
+ <else>
+ <date variable="issued">
+ <date-part name="year"/>
+ </date>
+ </else>
+ </choose>
+ </if>
+ <else>
+ <date variable="issued">
+ <date-part name="year"/>
+ </date>
+ </else>
+ </choose>
+ <text variable="year-suffix"/>
+ </group>
+ </macro>
+ <macro name="issued-citation">
+ <choose>
+ <if variable="issued">
+ <group delimiter="/">
+ <choose>
+ <if is-uncertain-date="original-date">
+ <group prefix="[" suffix="]" delimiter=" ">
+ <text term="circa" form="short"/>
+ <date variable="original-date">
+ <date-part name="year"/>
+ </date>
+ </group>
+ </if>
+ <else>
+ <date variable="original-date">
+ <date-part name="year"/>
+ </date>
+ </else>
+ </choose>
+ <choose>
+ <if is-uncertain-date="issued">
+ <group prefix="[" suffix="]" delimiter=" ">
+ <text term="circa" form="short"/>
+ <text macro="issued-year"/>
+ </group>
+ </if>
+ <else>
+ <text macro="issued-year"/>
+ </else>
+ </choose>
+ </group>
+ </if>
+ <else-if variable="status">
+ <text variable="status" text-case="lowercase"/>
+ <text variable="year-suffix" prefix="-"/>
+ </else-if>
+ <else>
+ <text term="no date" form="short"/>
+ <text variable="year-suffix" prefix="-"/>
+ </else>
+ </choose>
+ </macro>
+ <macro name="original-date">
+ <choose>
+ <if type="bill legal_case legislation" match="any"/>
+ <else-if type="speech">
+ <date variable="original-date" delimiter=" ">
+ <date-part name="month"/>
+ <date-part name="year"/>
+ </date>
+ </else-if>
+ <else-if type="article article-magazine article-newspaper broadcast interview pamphlet personal_communication post post-weblog treaty webpage" match="any">
+ <date variable="original-date" form="text"/>
+ </else-if>
+ <else>
+ <date variable="original-date">
+ <date-part name="year"/>
+ </date>
+ </else>
+ </choose>
+ </macro>
+ <macro name="original-published">
+ <!--This should be localized -->
+ <choose>
+ <if type="bill legal_case legislation" match="any"/>
+ <else-if type="interview motion_picture song" match="any">
+ <text value="Original work recorded"/>
+ </else-if>
+ <else-if type="broadcast">
+ <text value="Original work broadcast"/>
+ </else-if>
+ <else>
+ <text value="Original work published"/>
+ </else>
+ </choose>
+ </macro>
+ <macro name="edition">
+ <choose>
+ <if is-numeric="edition">
+ <group delimiter=" ">
+ <number variable="edition" form="ordinal"/>
+ <text term="edition" form="short"/>
+ </group>
+ </if>
+ <else>
+ <text variable="edition"/>
+ </else>
+ </choose>
+ </macro>
+ <macro name="locators">
+ <choose>
+ <if type="article-journal article-magazine figure review review-book" match="any">
+ <group delimiter=", ">
+ <group>
+ <text variable="volume" font-style="italic"/>
+ <text variable="issue" prefix="(" suffix=")"/>
+ </group>
+ <text variable="page"/>
+ </group>
+ </if>
+ <else-if type="article-newspaper">
+ <group delimiter=" ">
+ <label variable="page" form="short"/>
+ <text variable="page"/>
+ </group>
+ </else-if>
+ <else-if type="paper-conference">
+ <choose>
+ <if variable="collection-editor editor" match="any">
+ <text macro="locators-booklike"/>
+ </if>
+ <else>
+ <group delimiter=", ">
+ <group>
+ <text variable="volume" font-style="italic"/>
+ <text variable="issue" prefix="(" suffix=")"/>
+ </group>
+ <text variable="page"/>
+ </group>
+ </else>
+ </choose>
+ </else-if>
+ <else-if type="bill broadcast interview legal_case legislation patent post post-weblog speech treaty webpage" match="none">
+ <text macro="locators-booklike"/>
+ </else-if>
+ </choose>
+ </macro>
+ <macro name="locators-booklike">
+ <group delimiter=", ">
+ <text macro="edition"/>
+ <group delimiter=" ">
+ <text term="version" text-case="capitalize-first"/>
+ <text variable="version"/>
+ </group>
+ <choose>
+ <if variable="volume" match="any">
+ <choose>
+ <if is-numeric="volume" match="none"/>
+ <else-if variable="collection-title">
+ <choose>
+ <if variable="editor translator" match="none">
+ <choose>
+ <if variable="collection-number">
+ <group>
+ <text term="volume" form="short" text-case="capitalize-first" suffix=" "/>
+ <number variable="volume" form="numeric"/>
+ </group>
+ </if>
+ </choose>
+ </if>
+ </choose>
+ </else-if>
+ <else>
+ <group>
+ <text term="volume" form="short" text-case="capitalize-first" suffix=" "/>
+ <number variable="volume" form="numeric"/>
+ </group>
+ </else>
+ </choose>
+ </if>
+ <else>
+ <group>
+ <text term="volume" form="short" plural="true" text-case="capitalize-first" suffix=" "/>
+ <number variable="number-of-volumes" form="numeric" prefix="1&#8211;"/>
+ </group>
+ </else>
+ </choose>
+ <group>
+ <label variable="page" form="short" suffix=" "/>
+ <text variable="page"/>
+ </group>
+ </group>
+ </macro>
+ <macro name="citation-locator">
+ <group>
+ <choose>
+ <if locator="chapter">
+ <label variable="locator" text-case="capitalize-first"/>
+ </if>
+ <else>
+ <label variable="locator" form="short"/>
+ </else>
+ </choose>
+ <text variable="locator" prefix=" "/>
+ </group>
+ </macro>
+ <macro name="container">
+ <choose>
+ <if type="article article-journal article-magazine article-newspaper review review-book" match="any">
+ <group delimiter=", ">
+ <text macro="container-title"/>
+ <text macro="locators"/>
+ </group>
+ <choose>
+ <!--for advance online publication-->
+ <if variable="issued">
+ <choose>
+ <if variable="page issue" match="none">
+ <text variable="status" text-case="capitalize-first" prefix=". "/>
+ </if>
+ </choose>
+ </if>
+ </choose>
+ </if>
+ <else-if type="article dataset figure" match="any">
+ <choose>
+ <if variable="container-title">
+ <group delimiter=", ">
+ <text macro="container-title"/>
+ <text macro="locators"/>
+ </group>
+ <choose>
+ <!--for advance online publication-->
+ <if variable="issued">
+ <choose>
+ <if variable="page issue" match="none">
+ <text variable="status" text-case="capitalize-first" prefix=". "/>
+ </if>
+ </choose>
+ </if>
+ </choose>
+ </if>
+ </choose>
+ </else-if>
+ <!-- book is here to catch software with container titles -->
+ <else-if type="book" variable="container-title" match="all">
+ <group delimiter=" ">
+ <text term="in" text-case="capitalize-first" suffix=" "/>
+ <group delimiter=", ">
+ <text macro="container-contributors"/>
+ <group delimiter=" ">
+ <text macro="container-title"/>
+ <text macro="description-report" prefix="(" suffix=")"/>
+ <text macro="format-report" prefix="[" suffix="]"/>
+ </group>
+ </group>
+ </group>
+ </else-if>
+ <else-if type="report" variable="container-title" match="all">
+ <group delimiter=" ">
+ <text term="in" text-case="capitalize-first" suffix=" "/>
+ <group delimiter=", ">
+ <text macro="container-contributors"/>
+ <group delimiter=" ">
+ <text macro="container-title"/>
+ <text macro="description-report" prefix="(" suffix=")"/>
+ <text macro="format-report" prefix="[" suffix="]"/>
+ </group>
+ </group>
+ </group>
+ </else-if>
+ <else-if type="song" variable="container-title" match="all">
+ <group delimiter=" ">
+ <text term="in" text-case="capitalize-first" suffix=" "/>
+ <group delimiter=", ">
+ <text macro="container-contributors"/>
+ <group delimiter=" ">
+ <text macro="container-title"/>
+ <text macro="locators" prefix="(" suffix=")"/>
+ <group delimiter=", " prefix="[" suffix="]">
+ <text variable="genre" text-case="capitalize-first"/>
+ <text variable="medium" text-case="capitalize-first"/>
+ </group>
+ </group>
+ </group>
+ </group>
+ </else-if>
+ <else-if type="paper-conference">
+ <choose>
+ <if variable="editor collection-editor container-author" match="any">
+ <text macro="container-booklike"/>
+ </if>
+ <else>
+ <group delimiter=", ">
+ <text macro="container-title"/>
+ <text macro="locators"/>
+ </group>
+ </else>
+ </choose>
+ </else-if>
+ <else-if type="book">
+ <choose>
+ <!-- book and software should not cite collection-title, only container-title -->
+ <if variable="container-title">
+ <text macro="container-booklike"/>
+ </if>
+ </choose>
+ </else-if>
+ <else-if type="broadcast chapter entry entry-dictionary entry-encyclopedia graphic map speech" match="any">
+ <text macro="container-booklike"/>
+ </else-if>
+ <else-if type="bill legal_case legislation treaty" match="any">
+ <text macro="legal-cites"/>
+ </else-if>
+ </choose>
+ </macro>
+ <macro name="container-booklike">
+ <choose>
+ <if variable="container-title collection-title" match="any">
+ <group delimiter=" ">
+ <text term="in" text-case="capitalize-first"/>
+ <group delimiter=", ">
+ <text macro="container-contributors"/>
+ <choose>
+ <if variable="container-author editor translator" match="none">
+ <group delimiter=". ">
+ <group delimiter=": ">
+ <text variable="collection-title" font-style="italic" text-case="title"/>
+ <choose>
+ <if variable="collection-title">
+ <group delimiter=" ">
+ <text term="volume" form="short" font-style="italic" text-case="capitalize-first"/>
+ <number variable="collection-number" font-style="italic" form="numeric"/>
+ <choose>
+ <if variable="collection-number" match="none">
+ <number variable="volume" font-style="italic" form="numeric"/>
+ </if>
+ </choose>
+ </group>
+ </if>
+ </choose>
+ </group>
+ <!-- Replace with volume-title as that becomes available -->
+ <group delimiter=": ">
+ <text macro="container-title"/>
+ <choose>
+ <if variable="collection-title" is-numeric="volume" match="none">
+ <group delimiter=" ">
+ <text term="volume" form="short" font-style="italic" text-case="capitalize-first"/>
+ <text variable="volume" font-style="italic"/>
+ </group>
+ </if>
+ </choose>
+ </group>
+ </group>
+ </if>
+ <else>
+ <!-- Replace with volume-title as that becomes available -->
+ <group delimiter=": ">
+ <text macro="container-title"/>
+ <choose>
+ <if is-numeric="volume" match="none">
+ <group delimiter=" ">
+ <text term="volume" form="short" font-style="italic" text-case="capitalize-first"/>
+ <text variable="volume" font-style="italic"/>
+ </group>
+ </if>
+ </choose>
+ </group>
+ </else>
+ </choose>
+ </group>
+ <group delimiter="; " prefix="(" suffix=")">
+ <text macro="locators"/>
+ <names variable="container-author">
+ <label form="verb-short" suffix=" " text-case="title"/>
+ <name and="symbol" initialize-with=". " delimiter=", "/>
+ </names>
+ </group>
+ </group>
+ </if>
+ </choose>
+ </macro>
+ <macro name="container-title">
+ <choose>
+ <if type="article article-journal article-magazine article-newspaper dataset" match="any">
+ <text variable="container-title" font-style="italic" text-case="title"/>
+ </if>
+ <else-if type="paper-conference speech">
+ <choose>
+ <if variable="collection-editor container-author editor" match="any">
+ <text variable="container-title" font-style="italic"/>
+ </if>
+ <else>
+ <text variable="container-title" font-style="italic" text-case="title"/>
+ </else>
+ </choose>
+ </else-if>
+ <else-if type="bill legal_case legislation post-weblog webpage" match="none">
+ <text variable="container-title" font-style="italic"/>
+ </else-if>
+ </choose>
+ </macro>
+ <macro name="legal-cites">
+ <choose>
+ <if type="legal_case">
+ <group prefix=", " delimiter=" ">
+ <group delimiter=" ">
+ <choose>
+ <if variable="container-title">
+ <text variable="volume"/>
+ <text variable="container-title"/>
+ <group delimiter=" ">
+ <!--change to label variable="section" as that becomes available -->
+ <text term="section" form="symbol"/>
+ <text variable="section"/>
+ </group>
+ <text variable="page"/>
+ </if>
+ <else>
+ <group delimiter=" ">
+ <choose>
+ <if is-numeric="number">
+ <!-- Replace with term="number" if that becomes available -->
+ <text term="issue" form="short" text-case="capitalize-first"/>
+ </if>
+ </choose>
+ <text variable="number"/>
+ </group>
+ </else>
+ </choose>
+ </group>
+ <group prefix="(" suffix=")" delimiter=" ">
+ <text variable="authority"/>
+ <choose>
+ <if variable="container-title" match="any">
+ <!--Only print year for cases published in reporters-->
+ <date variable="issued" form="numeric" date-parts="year"/>
+ </if>
+ <else>
+ <date variable="issued" form="text"/>
+ </else>
+ </choose>
+ </group>
+ </group>
+ </if>
+ <else-if type="bill legislation" match="any">
+ <group prefix=", " delimiter=" ">
+ <group delimiter=", ">
+ <choose>
+ <if variable="number">
+ <!--There's a public law number-->
+ <text variable="number" prefix="Pub. L. No. "/>
+ <group delimiter=" ">
+ <!--change to label variable="section" as that becomes available -->
+ <text term="section" form="symbol"/>
+ <text variable="section"/>
+ </group>
+ <group delimiter=" ">
+ <text variable="volume"/>
+ <text variable="container-title"/>
+ <text variable="page-first"/>
+ </group>
+ </if>
+ <else>
+ <group delimiter=" ">
+ <text variable="volume"/>
+ <text variable="container-title"/>
+ <!--change to label variable="section" as that becomes available -->
+ <text term="section" form="symbol"/>
+ <text variable="section"/>
+ </group>
+ </else>
+ </choose>
+ </group>
+ <date variable="issued" prefix="(" suffix=")">
+ <date-part name="year"/>
+ </date>
+ </group>
+ </else-if>
+ <else-if type="treaty">
+ <group delimiter=" ">
+ <number variable="volume"/>
+ <text variable="container-title"/>
+ <text variable="page"/>
+ </group>
+ </else-if>
+ </choose>
+ </macro>
+ <citation et-al-min="6" et-al-use-first="1" et-al-subsequent-min="3" et-al-subsequent-use-first="1" disambiguate-add-year-suffix="true" disambiguate-add-names="true" disambiguate-add-givenname="true" collapse="year" givenname-disambiguation-rule="primary-name">
+ <sort>
+ <key macro="author" names-min="8" names-use-first="6"/>
+ <key macro="issued-sort"/>
+ </sort>
+ <layout prefix="(" suffix=")" delimiter="; ">
+ <group delimiter=", ">
+ <text macro="author-short"/>
+ <text macro="issued-citation"/>
+ <text macro="citation-locator"/>
+ </group>
+ </layout>
+ </citation>
+ <bibliography hanging-indent="true" et-al-min="8" et-al-use-first="6" et-al-use-last="true" entry-spacing="0" line-spacing="2">
+ <sort>
+ <key macro="author"/>
+ <key macro="issued-sort" sort="ascending"/>
+ <key macro="title"/>
+ </sort>
+ <layout>
+ <group suffix=".">
+ <group delimiter=". ">
+ <text macro="author"/>
+ <choose>
+ <if is-uncertain-date="issued">
+ <group prefix=" [" suffix="]" delimiter=" ">
+ <text term="circa" form="short"/>
+ <text macro="issued"/>
+ </group>
+ </if>
+ <else>
+ <text macro="issued" prefix=" (" suffix=")"/>
+ </else>
+ </choose>
+ <group delimiter=" ">
+ <text macro="title"/>
+ <choose>
+ <if variable="title interviewer" type="interview" match="any">
+ <group delimiter=" ">
+ <text macro="description"/>
+ <text macro="format"/>
+ </group>
+ </if>
+ <else>
+ <group delimiter=" ">
+ <text macro="format"/>
+ <text macro="description"/>
+ </group>
+ </else>
+ </choose>
+ </group>
+ <text macro="container"/>
+ </group>
+ <text macro="event" prefix=". "/>
+ </group>
+ <text macro="access" prefix=" "/>
+ <choose>
+ <if is-uncertain-date="original-date">
+ <group prefix=" [" suffix="]" delimiter=" ">
+ <text macro="original-published"/>
+ <text term="circa" form="short"/>
+ <text macro="original-date"/>
+ </group>
+ </if>
+ <else-if variable="original-date">
+ <group prefix=" (" suffix=")" delimiter=" ">
+ <text macro="original-published"/>
+ <text macro="original-date"/>
+ </group>
+ </else-if>
+ </choose>
+ </layout>
+ </bibliography>
+</style> \ No newline at end of file
diff --git a/support/texlab/src/citeproc/mod.rs b/support/texlab/src/citeproc/mod.rs
new file mode 100644
index 0000000000..9827c190f3
--- /dev/null
+++ b/support/texlab/src/citeproc/mod.rs
@@ -0,0 +1,69 @@
+mod name;
+mod ris;
+
+use self::ris::*;
+use crate::formatting::bibtex::{format_entry, format_string, BibtexFormattingParams};
+use crate::syntax::*;
+use bibutils::{InputFormat, OutputFormat};
+use citeproc::prelude::*;
+use citeproc_db::PredefinedLocales;
+use lsp_types::{MarkupContent, MarkupKind};
+use std::sync::Arc;
+
+static APA_STYLE: &str = include_str!("apa.csl");
+
+pub fn render_citation(tree: &BibtexSyntaxTree, key: &str) -> Option<MarkupContent> {
+ let reference: Reference = convert_to_ris(tree, key)?.into();
+
+ let html = generate_bibliography(reference)?;
+ let markdown = html2md::parse_html(&html).trim().to_owned();
+ if markdown == "" {
+ return None;
+ }
+
+ let content = MarkupContent {
+ kind: MarkupKind::Markdown,
+ value: markdown.replace("..", "."),
+ };
+ Some(content)
+}
+
+fn convert_to_ris(tree: &BibtexSyntaxTree, key: &str) -> Option<RisReference> {
+ let bib_params = BibtexFormattingParams::default();
+ let mut bib_code = String::new();
+
+ for string in tree.strings() {
+ bib_code.push_str(&format_string(string, &bib_params));
+ bib_code.push('\n');
+ }
+
+ let entry = tree.find_entry(key)?;
+ if let Some(crossref) = tree.resolve_crossref(entry) {
+ bib_code.push_str(&format_entry(crossref, &bib_params));
+ bib_code.push('\n');
+ }
+
+ bib_code.push_str(&format_entry(entry, &bib_params));
+ bib_code.push('\n');
+
+ let ris_code = bibutils::convert(bib_code, InputFormat::Biblatex, OutputFormat::Ris)?;
+ let ris_lib = RisLibrary::parse(ris_code.lines());
+ ris_lib
+ .references
+ .into_iter()
+ .find(|reference| reference.id.as_ref().map(AsRef::as_ref) == Some(key))
+}
+
+fn generate_bibliography(reference: Reference) -> Option<String> {
+ let locales = Arc::new(PredefinedLocales::bundled_en_us());
+ let mut processor = Processor::new(APA_STYLE, locales, false, SupportedFormat::Html).unwrap();
+ let cite = Cite::basic(&reference.id);
+ let cluster = Cluster2::Note {
+ id: 1,
+ note: IntraNote::Single(1),
+ cites: vec![cite],
+ };
+ processor.insert_reference(reference);
+ processor.init_clusters(vec![cluster]);
+ processor.get_bibliography().pop()
+}
diff --git a/support/texlab/src/citeproc/name/mod.rs b/support/texlab/src/citeproc/name/mod.rs
new file mode 100644
index 0000000000..7668d0fff8
--- /dev/null
+++ b/support/texlab/src/citeproc/name/mod.rs
@@ -0,0 +1,275 @@
+// Ported from: https://github.com/michel-kraemer/citeproc-java/blob/master/citeproc-java/grammars/InternalName.g4
+// Michel Kraemer
+// Apache License 2.0
+mod parser;
+
+use self::parser::NamesParser;
+use citeproc_io::Name;
+
+pub fn parse(input: &str) -> Vec<Name> {
+ let parser = NamesParser::new();
+ parser.parse(input).unwrap_or_else(|_| {
+ vec![Name::Literal {
+ literal: input.into(),
+ }]
+ })
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use citeproc_io::PersonName;
+
+ #[test]
+ fn test_family_only() {
+ let name = Name::Person(PersonName {
+ family: Some("Thompson".into()),
+ given: None,
+ non_dropping_particle: None,
+ dropping_particle: None,
+ suffix: None,
+ });
+ assert_eq!(parse("Thompson"), vec![name]);
+ }
+
+ #[test]
+ fn test_simple() {
+ let name = Name::Person(PersonName {
+ family: Some("Thompson".into()),
+ given: Some("Ken".into()),
+ non_dropping_particle: None,
+ dropping_particle: None,
+ suffix: None,
+ });
+ assert_eq!(parse("Ken Thompson"), vec![name]);
+ }
+
+ #[test]
+ fn test_middle_name() {
+ let name = Name::Person(PersonName {
+ family: Some("Ritchie".into()),
+ given: Some("Dennis M.".into()),
+ non_dropping_particle: None,
+ dropping_particle: None,
+ suffix: None,
+ });
+ assert_eq!(parse("Dennis M. Ritchie"), vec![name]);
+ }
+
+ #[test]
+ fn test_initials() {
+ let name = Name::Person(PersonName {
+ family: Some("Johnson".into()),
+ given: Some("S. C.".into()),
+ non_dropping_particle: None,
+ dropping_particle: None,
+ suffix: None,
+ });
+ assert_eq!(parse("S. C. Johnson"), vec![name]);
+ }
+
+ #[test]
+ fn test_non_dropping_particle() {
+ let name = Name::Person(PersonName {
+ family: Some("Gerwen".into()),
+ given: Some("Michael".into()),
+ non_dropping_particle: Some("van".into()),
+ dropping_particle: None,
+ suffix: None,
+ });
+ assert_eq!(parse("Michael van Gerwen"), vec![name]);
+ }
+
+ #[test]
+ fn test_non_dropping_particle_family_only() {
+ let name = Name::Person(PersonName {
+ family: Some("Gerwen".into()),
+ given: None,
+ non_dropping_particle: Some("van".into()),
+ dropping_particle: None,
+ suffix: None,
+ });
+ assert_eq!(parse("van Gerwen"), vec![name]);
+ }
+
+ #[test]
+ fn test_comma() {
+ let name = Name::Person(PersonName {
+ family: Some("Thompson".into()),
+ given: Some("Ken".into()),
+ non_dropping_particle: None,
+ dropping_particle: None,
+ suffix: None,
+ });
+ assert_eq!(parse("Thompson, Ken"), vec![name]);
+ }
+
+ #[test]
+ fn test_comma_junior() {
+ let name = Name::Person(PersonName {
+ family: Some("Friedman".into()),
+ given: Some("George".into()),
+ non_dropping_particle: None,
+ dropping_particle: None,
+ suffix: Some("Jr.".into()),
+ });
+ assert_eq!(parse("Friedman, Jr., George"), vec![name]);
+ }
+
+ #[test]
+ fn test_comma_no_junior() {
+ let name = Name::Person(PersonName {
+ family: Some("Familya Familyb".into()),
+ given: Some("Given".into()),
+ non_dropping_particle: None,
+ dropping_particle: None,
+ suffix: None,
+ });
+ assert_eq!(parse("Familya Familyb, Given"), vec![name]);
+ }
+
+ #[test]
+ fn test_comma_initials() {
+ let name = Name::Person(PersonName {
+ family: Some("Ritchie".into()),
+ given: Some("Dennis M.".into()),
+ non_dropping_particle: None,
+ dropping_particle: None,
+ suffix: None,
+ });
+ assert_eq!(parse("Ritchie, Dennis M."), vec![name]);
+ }
+
+ #[test]
+ fn test_comma_non_dropping_particle() {
+ let name = Name::Person(PersonName {
+ family: Some("Gerwen".into()),
+ given: Some("Michael".into()),
+ non_dropping_particle: Some("van".into()),
+ dropping_particle: None,
+ suffix: None,
+ });
+ assert_eq!(parse("van Gerwen, Michael"), vec![name]);
+ }
+
+ #[test]
+ fn test_comma_non_dropping_particles() {
+ let name = Name::Person(PersonName {
+ family: Some("Voort".into()),
+ given: Some("Vincent".into()),
+ non_dropping_particle: Some("Van der".into()),
+ dropping_particle: None,
+ suffix: None,
+ });
+ assert_eq!(parse("Van der Voort, Vincent"), vec![name]);
+ }
+
+ #[test]
+ fn test_and() {
+ let name1 = Name::Person(PersonName {
+ family: Some("Gerwen".into()),
+ given: Some("Michael".into()),
+ non_dropping_particle: Some("van".into()),
+ dropping_particle: None,
+ suffix: None,
+ });
+ let name2 = Name::Person(PersonName {
+ family: Some("Voort".into()),
+ given: Some("Vincent".into()),
+ non_dropping_particle: Some("van der".into()),
+ dropping_particle: None,
+ suffix: None,
+ });
+ assert_eq!(
+ parse("Michael van Gerwen and Vincent van der Voort"),
+ vec![name1, name2]
+ );
+ }
+
+ #[test]
+ fn test_and_comma1() {
+ let name1 = Name::Person(PersonName {
+ family: Some("Gerwen".into()),
+ given: Some("Michael".into()),
+ non_dropping_particle: Some("van".into()),
+ dropping_particle: None,
+ suffix: None,
+ });
+ let name2 = Name::Person(PersonName {
+ family: Some("Voort".into()),
+ given: Some("Vincent".into()),
+ non_dropping_particle: Some("Van der".into()),
+ dropping_particle: None,
+ suffix: None,
+ });
+ assert_eq!(
+ parse("van Gerwen, Michael and Van der Voort, Vincent"),
+ vec![name1, name2]
+ );
+ }
+
+ #[test]
+ fn test_and_comma2() {
+ let name1 = Name::Person(PersonName {
+ family: Some("Gerwen".into()),
+ given: Some("Michael".into()),
+ non_dropping_particle: Some("van".into()),
+ dropping_particle: None,
+ suffix: None,
+ });
+ let name2 = Name::Person(PersonName {
+ family: Some("Voort".into()),
+ given: Some("Vincent".into()),
+ non_dropping_particle: Some("van der".into()),
+ dropping_particle: None,
+ suffix: None,
+ });
+ assert_eq!(
+ parse("van Gerwen, Michael and van der Voort, Vincent"),
+ vec![name1, name2]
+ );
+ }
+
+ #[test]
+ fn test_and_comma_mix() {
+ let name1 = Name::Person(PersonName {
+ family: Some("Gerwen".into()),
+ given: Some("Michael".into()),
+ non_dropping_particle: Some("van".into()),
+ dropping_particle: None,
+ suffix: None,
+ });
+ let name2 = Name::Person(PersonName {
+ family: Some("Voort".into()),
+ given: Some("Vincent".into()),
+ non_dropping_particle: Some("van der".into()),
+ dropping_particle: None,
+ suffix: None,
+ });
+ assert_eq!(
+ parse("van Gerwen, Michael and Vincent van der Voort"),
+ vec![name1, name2]
+ );
+ }
+
+ #[test]
+ fn test_junior() {
+ let name = Name::Person(PersonName {
+ family: Some("Friedman".into()),
+ given: Some("George".into()),
+ non_dropping_particle: None,
+ dropping_particle: None,
+ suffix: Some("Jr.".into()),
+ });
+ assert_eq!(parse("George Friedman, Jr."), vec![name]);
+ }
+
+ #[test]
+ fn test_non_parseable() {
+ let literal = "Jerry Peek and Tim O'Reilly and Mike Loukides and other authors of the Nutshell handbooks";
+ let name = Name::Literal {
+ literal: literal.into(),
+ };
+ assert_eq!(parse(literal), vec![name]);
+ }
+}
diff --git a/support/texlab/src/citeproc/name/parser.lalrpop b/support/texlab/src/citeproc/name/parser.lalrpop
new file mode 100644
index 0000000000..556e3bd361
--- /dev/null
+++ b/support/texlab/src/citeproc/name/parser.lalrpop
@@ -0,0 +1,152 @@
+// Ported from: https://github.com/michel-kraemer/citeproc-java/blob/master/citeproc-java/grammars/InternalName.g4
+// Michel Kraemer
+// Apache License 2.0
+use citeproc_io::{Name, PersonName};
+use itertools::Itertools;
+
+grammar;
+
+pub Names: Vec<Name> = And<Name>;
+
+And<T>: Vec<T> = {
+ <v:(<T> "and")*> <e:T?> => match e {
+ None => v,
+ Some(e) => {
+ let mut v = v;
+ v.push(e);
+ v
+ }
+ }
+};
+
+Name: Name = {
+ <np1:UWord+> <np2:Von> <fam:Last> "," <fst:First> => {
+ let (fst1, fst2) = fst;
+ let name = PersonName {
+ family: Some(fam.join(" ")),
+ given: fst2,
+ non_dropping_particle: Some(format!("{} {}", np1.join(" "), np2)),
+ dropping_particle: None,
+ suffix: fst1,
+ };
+ Name::Person(name)
+ },
+ <np:Von> <fam:Last> "," <fst:First> => {
+ let (fst1, fst2) = fst;
+ let name = PersonName {
+ family: Some(fam.join(" ")),
+ given: fst2,
+ non_dropping_particle: Some(np),
+ dropping_particle: None,
+ suffix: fst1,
+ };
+ Name::Person(name)
+ },
+ <last:Last> "," <fst:First> => {
+ let (fst1, fst2) = fst;
+ let first_text = format!(
+ "{} {}",
+ fst1.as_ref().map(|s| s.as_str()).unwrap_or_default(),
+ fst2.as_ref().map(|s| s.as_str()).unwrap_or_default(),
+ ).trim().to_owned();
+
+ let name = if first_text == "Jr." {
+ if last.len() == 1 {
+ PersonName {
+ family: Some(last.join(" ")),
+ given: None,
+ non_dropping_particle: None,
+ dropping_particle: None,
+ suffix: Some(first_text),
+ }
+ } else {
+ let mut last = last.into_iter();
+ let given = last.next().map(ToOwned::to_owned);
+ PersonName {
+ family: Some(last.join(" ")),
+ given,
+ non_dropping_particle: None,
+ dropping_particle: None,
+ suffix: Some(first_text),
+ }
+ }
+ } else {
+ PersonName {
+ family: Some(last.join(" ")),
+ given: fst2,
+ non_dropping_particle: None,
+ dropping_particle: None,
+ suffix: fst1,
+ }
+ };
+ Name::Person(name)
+ },
+ <np:Von> <fam:Last> => {
+ let name = PersonName {
+ family: Some(fam.join(" ")),
+ given: None,
+ non_dropping_particle: Some(np),
+ dropping_particle: None,
+ suffix: None,
+ };
+ Name::Person(name)
+ },
+ <giv:UWord+> <np:Von> <fam:Last> => {
+ let name = PersonName {
+ family: Some(fam.join(" ")),
+ given: Some(giv.join(" ")),
+ non_dropping_particle: Some(np),
+ dropping_particle: None,
+ suffix: None,
+ };
+ Name::Person(name)
+ },
+ <giv:UWord+> <fam:Word> => {
+ let name = PersonName {
+ family: Some(fam.into()),
+ given: Some(giv.join(" ")),
+ non_dropping_particle: None,
+ dropping_particle: None,
+ suffix: None,
+ };
+ Name::Person(name)
+ },
+ <fam:Word> => {
+ let name = PersonName {
+ family: Some(fam.into()),
+ given: None,
+ non_dropping_particle: None,
+ dropping_particle: None,
+ suffix: None,
+ };
+ Name::Person(name)
+ },
+};
+
+First: (Option<String>, Option<String>) = {
+ <a:Word*> "," <b:Word*> => (Some(a.join(" ")), Some(b.join(" "))),
+ <a:Word*> => (None, Some(a.join(" "))),
+};
+
+Last: Vec<&'input str> = {
+ LWord => vec![(<>)],
+ UWord+ => (<>),
+};
+
+Von: String = {
+ LWord => String::from(<>),
+ <a:Von> <b:LWord> => format!("{} {}", a, b),
+ <a:Von> <b:UWord+> <c:LWord> => format!("{} {} {}", a, b.join(" "), c),
+};
+
+Word: &'input str = {
+ UWord => (<>),
+ LWord => (<>),
+};
+
+UWord: &'input str = r"[A-Z\u00C0-\uFFFF(?][A-Z\u00C0-\uFFFF(?a-z\-)&/.]+" => (<>);
+
+LWord: &'input str = r"[a-z\-)&/.][A-Z\u00C0-\uFFFF(?a-z\-)&/.]+" => (<>);
+
+
+
diff --git a/support/texlab/src/citeproc/ris.rs b/support/texlab/src/citeproc/ris.rs
new file mode 100644
index 0000000000..4a0379a698
--- /dev/null
+++ b/support/texlab/src/citeproc/ris.rs
@@ -0,0 +1,466 @@
+// Ported from: https://github.com/michel-kraemer/citeproc-java/tree/master/citeproc-java/templates
+// Michel Kraemer
+// Apache License 2.0
+use super::name;
+use citeproc_io::{Date, DateOrRange, Name, NumericValue, Reference};
+use csl::*;
+use fnv::FnvHashMap;
+use serde::{Deserialize, Serialize};
+
+#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)]
+#[serde(rename_all = "UPPERCASE")]
+pub enum RisType {
+ Abst,
+ Advs,
+ Aggr,
+ Ancient,
+ Art,
+ Bill,
+ Blog,
+ Book,
+ Case,
+ Chap,
+ Chart,
+ Clswk,
+ Comp,
+ Conf,
+ Cpaper,
+ Ctlg,
+ Data,
+ Dbase,
+ Dict,
+ Ebook,
+ Echap,
+ Edbook,
+ Ejour,
+ Elec,
+ Encyc,
+ Equa,
+ Figure,
+ Gen,
+ Govdoc,
+ Grant,
+ Hear,
+ Icomm,
+ Inpr,
+ Jfull,
+ Jour,
+ Legal,
+ Manscpt,
+ Map,
+ Mgzn,
+ Mpct,
+ Multi,
+ Music,
+ News,
+ Pamp,
+ Pat,
+ Pcomm,
+ Rprt,
+ Ser,
+ Slide,
+ Sound,
+ Stand,
+ Stat,
+ Std,
+ Thes,
+ Unpb,
+ Video,
+}
+
+impl RisType {
+ pub fn parse(ty: &str) -> Option<Self> {
+ let ty = format!("\"{}\"", ty);
+ serde_json::from_str(&ty).ok()
+ }
+
+ pub fn csl(self) -> CslType {
+ match self {
+ Self::Abst => CslType::Article,
+ Self::Advs => CslType::Article,
+ Self::Aggr => CslType::Dataset,
+ Self::Ancient => CslType::Article,
+ Self::Art => CslType::Article,
+ Self::Bill => CslType::Bill,
+ Self::Blog => CslType::Webpage,
+ Self::Book => CslType::Book,
+ Self::Case => CslType::LegalCase,
+ Self::Chap => CslType::Chapter,
+ Self::Chart => CslType::Article,
+ Self::Clswk => CslType::Article,
+ Self::Comp => CslType::Article,
+ Self::Conf => CslType::PaperConference,
+ Self::Cpaper => CslType::PaperConference,
+ Self::Ctlg => CslType::Book,
+ Self::Data => CslType::Dataset,
+ Self::Dbase => CslType::Dataset,
+ Self::Dict => CslType::EntryDictionary,
+ Self::Ebook => CslType::Book,
+ Self::Echap => CslType::Chapter,
+ Self::Edbook => CslType::Book,
+ Self::Ejour => CslType::ArticleJournal,
+ Self::Elec => CslType::Article,
+ Self::Encyc => CslType::EntryEncyclopedia,
+ Self::Equa => CslType::Article,
+ Self::Figure => CslType::Figure,
+ Self::Gen => CslType::Article,
+ Self::Govdoc => CslType::Legislation,
+ Self::Grant => CslType::Legislation,
+ Self::Hear => CslType::Article,
+ Self::Icomm => CslType::PersonalCommunication,
+ Self::Inpr => CslType::PaperConference,
+ Self::Jfull => CslType::ArticleJournal,
+ Self::Jour => CslType::ArticleJournal,
+ Self::Legal => CslType::Legislation,
+ Self::Manscpt => CslType::Manuscript,
+ Self::Map => CslType::Map,
+ Self::Mgzn => CslType::ArticleMagazine,
+ Self::Mpct => CslType::MotionPicture,
+ Self::Multi => CslType::Webpage,
+ Self::Music => CslType::Song,
+ Self::News => CslType::ArticleNewspaper,
+ Self::Pamp => CslType::Pamphlet,
+ Self::Pat => CslType::Patent,
+ Self::Pcomm => CslType::PersonalCommunication,
+ Self::Rprt => CslType::Report,
+ Self::Ser => CslType::Article,
+ Self::Slide => CslType::Article,
+ Self::Sound => CslType::Song,
+ Self::Stand => CslType::Article,
+ Self::Stat => CslType::Legislation,
+ Self::Std => CslType::Article,
+ Self::Thes => CslType::Thesis,
+ Self::Unpb => CslType::Article,
+ Self::Video => CslType::MotionPicture,
+ }
+ }
+}
+
+#[derive(Debug, PartialEq, Eq, Clone, Default, Serialize, Deserialize)]
+pub struct RisReference {
+ pub id: Option<String>,
+ pub ty: Option<RisType>,
+ pub editors: Vec<String>,
+ pub tertiary_authors: Vec<String>,
+ pub subsidiary_authors: Vec<String>,
+ pub abstrct: Option<String>,
+ pub author_address: Option<String>,
+ pub accession_number: Option<String>,
+ pub authors: Vec<String>,
+ pub book_or_conference: Option<String>,
+ pub custom1: Option<String>,
+ pub custom2: Option<String>,
+ pub custom3: Option<String>,
+ pub custom4: Option<String>,
+ pub custom5: Option<String>,
+ pub custom6: Option<String>,
+ pub custom7: Option<String>,
+ pub custom8: Option<String>,
+ pub caption: Option<String>,
+ pub call_number: Option<String>,
+ pub place: Option<String>,
+ pub date: Option<String>,
+ pub name_of_database: Option<String>,
+ pub doi: Option<String>,
+ pub database_provider: Option<String>,
+ pub end_page: Option<String>,
+ pub edition: Option<String>,
+ pub issue: Option<String>,
+ pub journal: Option<String>,
+ pub keywords: Vec<String>,
+ pub file_attachments: Vec<String>,
+ pub figure: Option<String>,
+ pub language: Option<String>,
+ pub label: Option<String>,
+ pub number: Option<String>,
+ pub type_of_work: Option<String>,
+ pub notes: Vec<String>,
+ pub number_of_volumes: Option<String>,
+ pub original_publication: Option<String>,
+ pub publisher: Option<String>,
+ pub year: Option<String>,
+ pub reviewed_item: Option<String>,
+ pub research_notes: Option<String>,
+ pub reprint_edition: Option<String>,
+ pub section: Option<String>,
+ pub isbn_or_issn: Option<String>,
+ pub start_page: Option<String>,
+ pub short_title: Option<String>,
+ pub primary_title: Option<String>,
+ pub secondardy_title: Option<String>,
+ pub tertiary_title: Option<String>,
+ pub translated_authors: Vec<String>,
+ pub title: Option<String>,
+ pub translated_title: Option<String>,
+ pub url: Option<String>,
+ pub volume: Option<String>,
+ pub access_date: Option<String>,
+}
+
+#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
+pub struct RisLibrary {
+ pub references: Vec<RisReference>,
+}
+
+impl RisLibrary {
+ pub fn parse<'a, I: Iterator<Item = &'a str>>(lines: I) -> Self {
+ let mut library = Self {
+ references: Vec::new(),
+ };
+
+ let mut reference: RisReference = RisReference::default();
+ for line in lines {
+ let line = line.trim();
+ if line == "" {
+ continue;
+ }
+
+ if line == "ER -" {
+ library.references.push(reference);
+ reference = RisReference::default();
+ continue;
+ }
+
+ let chars: Vec<_> = line.chars().collect();
+ if chars.len() < 7 || chars[4] != '-' {
+ continue;
+ }
+
+ let key: String = (&chars[..2]).into_iter().collect();
+ let value: String = (&chars[6..]).into_iter().collect();
+ match key.to_uppercase().as_str() {
+ "TY" => reference.ty = RisType::parse(&value),
+ "A2" => reference.editors.push(value),
+ "A3" => reference.tertiary_authors.push(value),
+ "A4" => reference.subsidiary_authors.push(value),
+ "AB" => reference.abstrct = Some(value),
+ "AD" => reference.author_address = Some(value),
+ "AN" => reference.accession_number = Some(value),
+ "AU" => reference.authors.push(value),
+ "BT" => reference.book_or_conference = Some(value),
+ "C1" => reference.custom1 = Some(value),
+ "C2" => reference.custom2 = Some(value),
+ "C3" => reference.custom3 = Some(value),
+ "C4" => reference.custom4 = Some(value),
+ "C5" => reference.custom5 = Some(value),
+ "C6" => reference.custom6 = Some(value),
+ "C7" => reference.custom7 = Some(value),
+ "C8" => reference.custom8 = Some(value),
+ "CA" => reference.caption = Some(value),
+ "CN" => reference.call_number = Some(value),
+ "CY" => reference.place = Some(value),
+ "DA" => reference.date = Some(value),
+ "DB" => reference.name_of_database = Some(value),
+ "DO" => reference.doi = Some(value),
+ "DP" => reference.database_provider = Some(value),
+ "ED" => reference.editors.push(value),
+ "EP" => reference.end_page = Some(value),
+ "ET" => reference.edition = Some(value),
+ "ID" => reference.id = Some(value),
+ "IS" => reference.issue = Some(value),
+ "JO" => reference.journal = Some(value),
+ "J2" => reference.journal = Some(value),
+ "KW" => reference.keywords.push(value),
+ "L1" => reference.file_attachments.push(value),
+ "L4" => reference.figure = Some(value),
+ "LA" => reference.language = Some(value),
+ "LB" => reference.label = Some(value),
+ "M1" => reference.number = Some(value),
+ "M3" => reference.type_of_work = Some(value),
+ "N1" => reference.notes.push(value),
+ "N2" => reference.abstrct = Some(value),
+ "NV" => reference.number_of_volumes = Some(value),
+ "OP" => reference.original_publication = Some(value),
+ "PB" => reference.publisher = Some(value),
+ "PY" => reference.year = Some(value),
+ "RI" => reference.reviewed_item = Some(value),
+ "RN" => reference.research_notes = Some(value),
+ "RP" => reference.reprint_edition = Some(value),
+ "SE" => reference.section = Some(value),
+ "SN" => reference.isbn_or_issn = Some(value),
+ "SP" => reference.start_page = Some(value),
+ "ST" => reference.short_title = Some(value),
+ "T1" => reference.primary_title = Some(value),
+ "T2" => reference.secondardy_title = Some(value),
+ "T3" => reference.tertiary_title = Some(value),
+ "TA" => reference.translated_authors.push(value),
+ "TI" => reference.title = Some(value),
+ "TT" => reference.translated_title = Some(value),
+ "U1" => reference.type_of_work = Some(value),
+ "UR" => reference.url = Some(value),
+ "VL" => reference.volume = Some(value),
+ "Y2" => reference.access_date = Some(value),
+ _ => (),
+ }
+ }
+ library
+ }
+}
+
+impl Into<Reference> for RisReference {
+ fn into(self) -> Reference {
+ let csl_type = self.ty.expect("RIS type is missing").csl();
+ let mut date: FnvHashMap<DateVariable, DateOrRange> = FnvHashMap::default();
+ let mut name: FnvHashMap<NameVariable, Vec<Name>> = FnvHashMap::default();
+ let mut number: FnvHashMap<NumberVariable, NumericValue> = FnvHashMap::default();
+ let mut ordinary: FnvHashMap<Variable, String> = FnvHashMap::default();
+
+ if let Some(access_date) = self.access_date {
+ date.insert(DateVariable::Accessed, parse_date_or_range(access_date));
+ }
+
+ name.insert(NameVariable::Author, parse_authors(self.authors));
+ name.insert(NameVariable::Editor, parse_authors(self.editors));
+
+ if let Some(container_title) = self
+ .journal
+ .or(self.name_of_database)
+ .or(self.book_or_conference)
+ {
+ ordinary.insert(Variable::ContainerTitle, container_title.clone());
+ ordinary.insert(Variable::CollectionTitle, container_title);
+ }
+
+ if let Some(value) = self.date.or(self.year) {
+ let value = parse_date_or_range(value);
+ date.insert(DateVariable::Issued, value.clone());
+ date.insert(DateVariable::EventDate, value);
+ }
+
+ if let Some(url) = self.url {
+ ordinary.insert(Variable::URL, url);
+ }
+
+ let notes = self.notes;
+ ordinary.insert(
+ Variable::Note,
+ self.research_notes.unwrap_or_else(|| notes.join("\n")),
+ );
+
+ if let Some(issue) = self.issue {
+ number.insert(NumberVariable::Issue, parse_number(issue));
+ }
+
+ if let Some(num) = self.number {
+ number.insert(NumberVariable::Number, parse_number(num));
+ }
+
+ if let Some(place) = self.place {
+ ordinary.insert(Variable::EventPlace, place.clone());
+ ordinary.insert(Variable::PublisherPlace, place.clone());
+ }
+
+ if let Some(abstrct) = self.abstrct {
+ ordinary.insert(Variable::Abstract, abstrct);
+ }
+
+ if let Some(call_number) = self.call_number {
+ ordinary.insert(Variable::CallNumber, call_number);
+ }
+
+ if let Some(doi) = self.doi {
+ ordinary.insert(Variable::DOI, doi);
+ }
+
+ if let Some(edition) = self.edition {
+ number.insert(NumberVariable::Edition, parse_number(edition));
+ }
+
+ if let Some(isbn_or_issn) = self.isbn_or_issn {
+ ordinary.insert(Variable::ISBN, isbn_or_issn.clone());
+ ordinary.insert(Variable::ISSN, isbn_or_issn);
+ }
+
+ ordinary.insert(Variable::Keyword, self.keywords.join(", "));
+
+ if let Some(number_of_volumes) = self.number_of_volumes {
+ number.insert(
+ NumberVariable::NumberOfVolumes,
+ parse_number(number_of_volumes),
+ );
+ }
+
+ if let Some(original_publication) = self.original_publication {
+ ordinary.insert(Variable::OriginalTitle, original_publication);
+ }
+
+ match (self.start_page, self.end_page) {
+ (Some(start_page), Some(end_page)) => {
+ number.insert(
+ NumberVariable::Page,
+ NumericValue::Str(format!("{}-{}", start_page, end_page)),
+ );
+ }
+ (Some(page), None) | (None, Some(page)) => {
+ number.insert(NumberVariable::Page, parse_number(page));
+ }
+ (None, None) => {}
+ }
+
+ if let Some(publisher) = self.publisher {
+ ordinary.insert(Variable::Publisher, publisher);
+ }
+
+ if let Some(reviewed_item) = self.reviewed_item {
+ ordinary.insert(Variable::ReviewedTitle, reviewed_item);
+ }
+
+ if let Some(section) = self.section {
+ ordinary.insert(Variable::Section, section);
+ }
+
+ if let Some(short_title) = self.short_title {
+ ordinary.insert(Variable::TitleShort, short_title);
+ }
+
+ if let Some(title) = self.title {
+ ordinary.insert(Variable::Title, title);
+ }
+
+ if let Some(volume) = self.volume {
+ number.insert(NumberVariable::Volume, parse_number(volume));
+ }
+
+ Reference {
+ id: Atom::from(self.id.or(self.label).expect("RIS id is missing").as_str()),
+ csl_type,
+ language: None,
+ name,
+ number,
+ date,
+ ordinary,
+ }
+ }
+}
+
+fn parse_number(value: String) -> NumericValue {
+ match value.parse() {
+ Ok(value) => NumericValue::num(value),
+ Err(_) => NumericValue::Str(value),
+ }
+}
+
+fn parse_authors(authors: Vec<String>) -> Vec<Name> {
+ authors
+ .into_iter()
+ .flat_map(|author| name::parse(&author))
+ .collect()
+}
+
+fn parse_date_or_range(value: String) -> DateOrRange {
+ parse_date(&value)
+ .map(DateOrRange::Single)
+ .unwrap_or_else(|| DateOrRange::Literal(value))
+}
+
+fn parse_date(value: &str) -> Option<Date> {
+ let mut parts = value.split('/');
+ let year: i32 = parts.next()?.parse().ok()?;
+ match parts.next().and_then(|p| p.parse().ok()) {
+ Some(month) => match parts.next().and_then(|p| p.parse().ok()) {
+ Some(day) => Some(Date::new(year, month, day)),
+ None => Some(Date::new(year, month, 0)),
+ },
+ None => Some(Date::new(year, 0, 0)),
+ }
+}