update packages

This commit is contained in:
2022-01-04 21:35:17 +01:00
parent 1d5275c946
commit 8de00e5202
700 changed files with 42441 additions and 85378 deletions

View File

@@ -0,0 +1,357 @@
<?xml version="1.0" encoding="utf-8"?>
<locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0" xml:lang="en-US">
<info>
<translator>
<name>Andrew Dunning</name>
</translator>
<translator>
<name>Sebastian Karcher</name>
</translator>
<translator>
<name>Rintze M. Zelle</name>
</translator>
<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 &amp; translator</single>
<multiple>editors &amp; 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. &amp; tran.</single>
<multiple>eds. &amp; 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 &amp; 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. &amp; 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>

View File

@@ -0,0 +1,341 @@
<?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="sort-only">
<info>
<title>American Psychological Association 5th edition</title>
<title-short>APA (5th ed.)</title-short>
<id>http://www.zotero.org/styles/apa-5th-edition</id>
<link href="http://www.zotero.org/styles/apa-5th-edition" rel="self"/>
<link href="http://rdc.libguides.com/content.php?pid=63487" rel="documentation"/>
<author>
<name>Simon Kornblith</name>
<email>simon@simonster.com</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>2020-03-23T14:28:18+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="fr">
<terms>
<term name="editor" form="short">
<single>éd.</single>
<multiple>éds.</multiple>
</term>
</terms>
</locale>
<macro name="container-contributors">
<choose>
<if type="chapter paper-conference" match="any">
<text term="in" text-case="capitalize-first" suffix=" "/>
<names variable="editor" delimiter=", " suffix=", ">
<name and="symbol" initialize-with=". " delimiter=", "/>
<label form="short" prefix=" (" text-case="capitalize-first" suffix=")"/>
<substitute>
<names variable="translator"/>
</substitute>
</names>
</if>
</choose>
</macro>
<macro name="secondary-contributors">
<choose>
<if type="chapter paper-conference" match="none">
<names variable="translator" delimiter=", " prefix=" (" suffix=")">
<name and="symbol" initialize-with=". " delimiter=", "/>
<label form="short" prefix=", " text-case="capitalize-first"/>
<substitute>
<names variable="editor"/>
</substitute>
</names>
</if>
</choose>
</macro>
<macro name="author">
<names variable="author">
<name name-as-sort-order="all" and="symbol" sort-separator=", " initialize-with=". " delimiter=", " delimiter-precedes-last="always"/>
<label form="short" prefix=" (" suffix=")" text-case="capitalize-first"/>
<substitute>
<names variable="editor"/>
<names variable="translator"/>
<text macro="title"/>
</substitute>
</names>
</macro>
<macro name="author-short">
<names variable="author">
<name form="short" and="symbol" delimiter=", " initialize-with=". "/>
<substitute>
<names variable="editor"/>
<names variable="translator"/>
<choose>
<if type="bill book graphic legal_case legislation motion_picture report song" match="any">
<text variable="title" form="short" font-style="italic"/>
</if>
<else>
<text variable="title" form="short" quotes="true"/>
</else>
</choose>
</substitute>
</names>
</macro>
<macro name="access">
<choose>
<if type="thesis">
<choose>
<if variable="archive" match="any">
<group>
<text term="retrieved" text-case="capitalize-first" suffix=" "/>
<text term="from" suffix=" "/>
<text variable="archive" suffix="."/>
<text variable="archive_location" prefix=" (" suffix=")"/>
</group>
</if>
<else>
<group>
<text term="retrieved" text-case="capitalize-first" suffix=" "/>
<date variable="accessed" suffix=", ">
<date-part name="month" suffix=" "/>
<date-part name="day" suffix=", "/>
<date-part name="year"/>
</date>
<text term="from" suffix=" "/>
<text variable="URL"/>
</group>
</else>
</choose>
</if>
<else>
<choose>
<if variable="URL">
<choose>
<if variable="archive">
<group>
<text term="retrieved" text-case="capitalize-first" suffix=" "/>
<text term="from" suffix=" "/>
<text variable="archive" suffix="."/>
</group>
</if>
<else>
<group>
<text term="retrieved" text-case="capitalize-first" suffix=" "/>
<date variable="accessed" suffix=", ">
<date-part name="month" suffix=" "/>
<date-part name="day" suffix=", "/>
<date-part name="year"/>
</date>
<group>
<text term="from" suffix=" "/>
<text variable="URL"/>
</group>
</group>
</else>
</choose>
</if>
</choose>
</else>
</choose>
</macro>
<macro name="title">
<choose>
<if type="report thesis" match="any">
<text variable="title" font-style="italic"/>
<group prefix=" (" suffix=")">
<text variable="genre"/>
<text variable="number" prefix=" No. "/>
</group>
</if>
<else-if type="bill book graphic legal_case legislation manuscript motion_picture report song speech" match="any">
<text variable="title" font-style="italic"/>
</else-if>
<else>
<text variable="title"/>
</else>
</choose>
</macro>
<macro name="publisher">
<choose>
<if type="report" match="any">
<group delimiter=": ">
<text variable="publisher-place"/>
<text variable="publisher"/>
</group>
</if>
<else-if type="thesis" match="any">
<group delimiter=", ">
<text variable="publisher"/>
<text variable="publisher-place"/>
</group>
</else-if>
<else>
<choose>
<if variable="event" match="none">
<text variable="genre" suffix=", "/>
</if>
</choose>
<group delimiter=": ">
<text variable="publisher-place"/>
<text variable="publisher"/>
</group>
</else>
</choose>
</macro>
<macro name="event">
<choose>
<if variable="event">
<choose>
<if variable="genre" match="none">
<text term="presented at" text-case="capitalize-first" suffix=" "/>
<text variable="event"/>
</if>
<else>
<group delimiter=" ">
<text variable="genre" text-case="capitalize-first"/>
<text term="presented at"/>
<text variable="event"/>
</group>
</else>
</choose>
</if>
</choose>
</macro>
<macro name="issued">
<choose>
<if variable="issued">
<group prefix=" (" suffix=").">
<date variable="issued">
<date-part name="year"/>
</date>
<choose>
<if type="article-journal bill book chapter graphic legal_case legislation motion_picture paper-conference report song" match="none">
<date variable="issued">
<date-part prefix=", " name="month"/>
<date-part prefix=" " name="day"/>
</date>
</if>
</choose>
</group>
</if>
<else>
<text prefix=" (" term="no date" suffix=")." form="short"/>
</else>
</choose>
</macro>
<macro name="issued-year">
<choose>
<if variable="issued">
<date variable="issued">
<date-part name="year"/>
</date>
</if>
<else>
<text term="no date" form="short"/>
</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" suffix="."/>
</else>
</choose>
</macro>
<macro name="locators">
<choose>
<if type="article-journal article-magazine article-newspaper" match="any">
<group prefix=", " delimiter=", ">
<group>
<text variable="volume" font-style="italic"/>
<text variable="issue" prefix="(" suffix=")"/>
</group>
<text variable="page"/>
</group>
</if>
<else-if type="bill book chapter graphic legal_case legislation motion_picture paper-conference report song" match="any">
<group prefix=" (" suffix=")" delimiter=", ">
<text macro="edition"/>
<group>
<text term="volume" form="short" plural="true" text-case="capitalize-first" suffix=" "/>
<number variable="number-of-volumes" form="numeric" prefix="1-"/>
</group>
<group>
<text term="volume" form="short" text-case="capitalize-first" suffix=" "/>
<number variable="volume" form="numeric"/>
</group>
<group>
<label variable="page" form="short" suffix=" "/>
<text variable="page"/>
</group>
</group>
</else-if>
</choose>
</macro>
<macro name="citation-locator">
<group>
<label variable="locator" form="short"/>
<text variable="locator" prefix=" "/>
</group>
</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" givenname-disambiguation-rule="primary-name" collapse="year">
<sort>
<key macro="author"/>
<key macro="issued-year"/>
</sort>
<layout prefix="(" suffix=")" delimiter="; ">
<group delimiter=", ">
<text macro="author-short"/>
<text macro="issued-year"/>
<text macro="citation-locator"/>
</group>
</layout>
</citation>
<bibliography hanging-indent="true" et-al-min="8" et-al-use-first="7" entry-spacing="0" line-spacing="2">
<sort>
<key macro="author"/>
<key macro="issued-year" sort="ascending"/>
</sort>
<layout>
<group suffix=".">
<text macro="author" suffix="."/>
<text macro="issued" suffix=" "/>
<group delimiter=". ">
<text macro="title"/>
<group>
<text macro="container-contributors"/>
<text macro="secondary-contributors"/>
<group delimiter=", ">
<text variable="container-title" font-style="italic"/>
<text variable="collection-title"/>
</group>
</group>
</group>
<text macro="locators"/>
<group delimiter=", " prefix=". ">
<text macro="event"/>
<text macro="publisher"/>
</group>
</group>
<text macro="access" prefix=". "/>
</layout>
</bibliography>
</style>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,657 @@
<?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 16th edition (author-date)</title>
<id>http://www.zotero.org/styles/chicago-author-date-16th-edition</id>
<link href="http://www.zotero.org/styles/chicago-author-date-16th-edition" 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>
<contributor>
<name>Brenton M. Wiernik</name>
</contributor>
<category citation-format="author-date"/>
<category field="generic-base"/>
<summary>The author-date variant of the Chicago style</summary>
<updated>2020-04-26T18:22:50+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">edited and translated by</term>
<term name="translator" form="short">trans.</term>
</terms>
</locale>
<macro name="secondary-contributors">
<choose>
<if type="chapter entry-dictionary entry-encyclopedia 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 entry-dictionary entry-encyclopedia 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" delimiter=" ">
<date-part name="month"/>
<date-part name="day"/>
</date>
</if>
</choose>
<choose>
<if variable="issued" match="none">
<group delimiter=" ">
<text term="accessed" text-case="capitalize-first"/>
<date variable="accessed" delimiter=" ">
<date-part name="month"/>
<date-part name="day"/>
</date>
</group>
</if>
</choose>
<choose>
<if type="legal_case" match="none">
<choose>
<if variable="DOI">
<text variable="DOI" prefix="doi:"/>
</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 entry-dictionary entry-encyclopedia 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 entry-dictionary entry-encyclopedia 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 entry-dictionary entry-encyclopedia 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 entry-dictionary entry-encyclopedia paper-conference" match="any">
<text macro="container-prefix" suffix=" "/>
</if>
</choose>
<choose>
<if type="legal_case" match="none">
<text variable="container-title" text-case="title" font-style="italic"/>
</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="accessed">
<date variable="accessed">
<date-part name="year"/>
</date>
</else-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="accessed">
<date variable="accessed">
<date-part name="year"/>
</date>
</else-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 delimiter=" ">
<choose>
<if variable="genre">
<text term="presented at"/>
</if>
<else>
<text term="presented at" text-case="capitalize-first"/>
</else>
</choose>
<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">
<text macro="day-month" 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="&#8212;&#8212;&#8212;" 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>

View File

@@ -0,0 +1,239 @@
<?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" default-locale="en-US">
<info>
<title>Elsevier - Harvard (with titles)</title>
<id>http://www.zotero.org/styles/elsevier-harvard</id>
<link href="http://www.zotero.org/styles/elsevier-harvard" rel="self"/>
<link href="http://www.zotero.org/styles/ecology-letters" rel="template"/>
<link href="http://www.elsevier.com/journals/biological-conservation/0006-3207/guide-for-authors#68000" rel="documentation"/>
<author>
<name>David Kaplan</name>
<email>david.kaplan@ird.fr</email>
</author>
<contributor>
<name>Simon Kornblith</name>
<email>simon@simonster.com</email>
</contributor>
<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="biology"/>
<category field="generic-base"/>
<updated>2014-03-04T00:09: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>
<macro name="container">
<choose>
<if type="chapter paper-conference" match="any">
<text term="in" prefix=", " suffix=": "/>
<names variable="editor translator" delimiter=", " suffix=", ">
<name name-as-sort-order="all" sort-separator=", " initialize-with="." delimiter=", " delimiter-precedes-last="always"/>
<label form="short" text-case="capitalize-first" prefix=" (" suffix=")"/>
</names>
<group delimiter=", ">
<text variable="container-title" text-case="title"/>
<text variable="collection-title" text-case="title"/>
</group>
</if>
<else-if type="bill book graphic legal_case legislation motion_picture report song" match="any">
<group prefix=", " delimiter=", ">
<text variable="container-title"/>
<text variable="collection-title"/>
</group>
</else-if>
<else>
<group prefix=". " delimiter=", ">
<text variable="container-title" form="short"/>
<text variable="collection-title"/>
</group>
</else>
</choose>
</macro>
<macro name="author">
<names variable="author">
<name name-as-sort-order="all" sort-separator=", " initialize-with="." delimiter=", " delimiter-precedes-last="always"/>
<label form="short" prefix=" (" suffix=")" text-case="capitalize-first"/>
<substitute>
<names variable="editor"/>
<names variable="translator"/>
<text macro="title"/>
</substitute>
</names>
</macro>
<macro name="author-short">
<names variable="author">
<name form="short" and="text" delimiter=", " initialize-with=". "/>
<substitute>
<names variable="editor"/>
<names variable="translator"/>
<choose>
<if type="bill book graphic legal_case legislation motion_picture report song" match="any">
<text variable="title" form="short" font-style="italic"/>
</if>
<else>
<text variable="title" form="short" quotes="true"/>
</else>
</choose>
</substitute>
</names>
</macro>
<macro name="access">
<choose>
<if variable="DOI">
<text variable="DOI" prefix="https://doi.org/"/>
</if>
<else-if type="webpage post-weblog" match="any">
<group delimiter=" ">
<text value="URL"/>
<text variable="URL"/>
<group prefix="(" suffix=").">
<text term="accessed" suffix=" "/>
<date variable="accessed">
<date-part name="month" form="numeric" suffix="."/>
<date-part name="day" suffix="."/>
<date-part name="year" form="short"/>
</date>
</group>
</group>
</else-if>
</choose>
</macro>
<macro name="title">
<choose>
<if type="report thesis" match="any">
<text variable="title"/>
<group prefix=" (" suffix=")" delimiter=" ">
<text variable="genre"/>
<text variable="number" prefix="No. "/>
</group>
</if>
<else-if type="bill book graphic legal_case legislation motion_picture report song speech" match="any">
<text variable="title"/>
<text macro="edition" prefix=", "/>
</else-if>
<else-if type="webpage">
<text variable="title"/>
<text value="WWW Document" prefix=" [" suffix="]"/>
</else-if>
<else>
<text variable="title"/>
</else>
</choose>
</macro>
<macro name="publisher">
<group delimiter=", ">
<text variable="publisher"/>
<text variable="publisher-place"/>
</group>
</macro>
<macro name="event">
<choose>
<if variable="event">
<text term="presented at" text-case="capitalize-first" suffix=" "/>
<text variable="event"/>
</if>
</choose>
</macro>
<macro name="issued">
<choose>
<if variable="issued">
<date variable="issued">
<date-part name="year"/>
</date>
</if>
<else>
<text term="no date" form="short"/>
</else>
</choose>
</macro>
<macro name="edition">
<group delimiter=" ">
<choose>
<if is-numeric="edition">
<number variable="edition" form="ordinal"/>
</if>
<else>
<text variable="edition" suffix="."/>
</else>
</choose>
<text value="ed"/>
</group>
</macro>
<macro name="locators">
<choose>
<if type="article-journal article-magazine article-newspaper" match="any">
<group prefix=" " delimiter=", ">
<group>
<text variable="volume"/>
</group>
<text variable="page"/>
</group>
</if>
<else-if type="bill book graphic legal_case legislation motion_picture report song thesis" match="any">
<group delimiter=", " prefix=". ">
<text macro="event"/>
<text macro="publisher"/>
</group>
</else-if>
<else-if type="chapter paper-conference" match="any">
<group delimiter=", " prefix=". ">
<text macro="event"/>
<text macro="publisher"/>
<group>
<label variable="page" form="short" suffix=" "/>
<text variable="page"/>
</group>
</group>
</else-if>
<else-if type="patent">
<text variable="number" prefix=". "/>
</else-if>
</choose>
</macro>
<citation et-al-min="3" et-al-use-first="1" disambiguate-add-givenname="true" disambiguate-add-year-suffix="true" collapse="year" cite-group-delimiter=", ">
<sort>
<key macro="author"/>
<key macro="issued" sort="descending"/>
</sort>
<layout prefix="(" suffix=")" delimiter="; ">
<group delimiter=", ">
<text macro="author-short"/>
<text macro="issued"/>
<group delimiter=" ">
<label variable="locator" form="short"/>
<text variable="locator"/>
</group>
</group>
</layout>
</citation>
<bibliography hanging-indent="true" entry-spacing="0" line-spacing="1">
<sort>
<key macro="author"/>
<key macro="issued" sort="descending"/>
</sort>
<layout>
<group suffix=".">
<text macro="author" suffix=","/>
<text macro="issued" prefix=" "/>
<group prefix=". ">
<text macro="title"/>
<text macro="container"/>
<text macro="locators"/>
</group>
</group>
<text macro="access" prefix=". "/>
</layout>
</bibliography>
</style>

View File

@@ -0,0 +1,149 @@
<?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="sort-only" default-locale="en-US">
<info>
<title>Elsevier (numeric, with titles)</title>
<id>http://www.zotero.org/styles/elsevier-with-titles</id>
<link href="http://www.zotero.org/styles/elsevier-with-titles" rel="self"/>
<link href="http://www.zotero.org/styles/elsevier-without-titles" rel="template"/>
<link href="http://www.elsevier.com/journals/journal-of-hazardous-materials/0304-3894/guide-for-authors#68001" rel="documentation"/>
<author>
<name>Richard Karnesky</name>
<email>karnesky+zotero@gmail.com</email>
<uri>http://arc.nucapt.northwestern.edu/Richard_Karnesky</uri>
</author>
<contributor>
<name>Rintze Zelle</name>
<uri>http://twitter.com/rintzezelle</uri>
</contributor>
<category citation-format="numeric"/>
<category field="generic-base"/>
<summary>A style for many of Elsevier's journals that includes article titles in the reference list</summary>
<updated>2019-10-15T15:14:08+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>
<macro name="author">
<names variable="author">
<name initialize-with="." delimiter=", " delimiter-precedes-last="always"/>
<label form="short" prefix=", "/>
<substitute>
<names variable="editor"/>
<names variable="translator"/>
</substitute>
</names>
</macro>
<macro name="editor">
<names variable="editor">
<name initialize-with="." delimiter=", " delimiter-precedes-last="always"/>
<label form="short" prefix=" (" text-case="capitalize-first" suffix=")"/>
</names>
</macro>
<macro name="year-date">
<choose>
<if variable="issued">
<date variable="issued">
<date-part name="year"/>
</date>
</if>
<else>
<text term="no date" form="short"/>
</else>
</choose>
</macro>
<macro name="publisher">
<text variable="publisher" suffix=", "/>
<text variable="publisher-place" suffix=", "/>
<text macro="year-date"/>
</macro>
<macro name="edition">
<!--TODO: CSL should have low numeric be text (e.g. '3'->'third')-->
<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="access">
<choose>
<if variable="URL">
<text variable="URL"/>
<group prefix=" (" suffix=")" delimiter=" ">
<text term="accessed"/>
<date variable="accessed" form="text"/>
</group>
</if>
</choose>
</macro>
<citation collapse="citation-number">
<sort>
<key variable="citation-number"/>
</sort>
<layout prefix="[" suffix="]" delimiter=",">
<text variable="citation-number"/>
</layout>
</citation>
<bibliography entry-spacing="0" second-field-align="flush">
<layout suffix=".">
<text variable="citation-number" prefix="[" suffix="]"/>
<text macro="author" suffix=", "/>
<choose>
<if type="bill book graphic legal_case legislation motion_picture report song" match="any">
<group delimiter=", ">
<text variable="title"/>
<text macro="edition"/>
<text macro="publisher"/>
</group>
</if>
<else-if type="chapter paper-conference" match="any">
<text variable="title" suffix=", "/>
<text term="in" suffix=": "/>
<text macro="editor" suffix=", "/>
<text variable="container-title" form="short" text-case="title" suffix=", "/>
<text macro="edition" suffix=", "/>
<text macro="publisher"/>
<group delimiter=" ">
<label variable="page" form="short" prefix=": "/>
<text variable="page"/>
</group>
</else-if>
<else-if type="patent">
<group delimiter=", ">
<text variable="title"/>
<text variable="number"/>
<text macro="year-date"/>
</group>
</else-if>
<else-if type="thesis">
<group delimiter=", ">
<text variable="title"/>
<text variable="genre"/>
<text variable="publisher"/>
<text macro="year-date"/>
</group>
</else-if>
<else>
<group delimiter=" ">
<text variable="title" suffix=","/>
<text variable="container-title" form="short" text-case="title" suffix="."/>
<text variable="volume"/>
<text macro="year-date" prefix="(" suffix=")"/>
<text variable="page" form="short"/>
</group>
</else>
</choose>
<choose>
<if variable="DOI">
<text variable="DOI" prefix=". https://doi.org/"/>
</if>
<else>
<text macro="access" prefix=". "/>
</else>
</choose>
</layout>
</bibliography>
</style>

View File

@@ -1,214 +0,0 @@
<?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="sort-only" page-range-format="expanded" default-locale="en-US">
<info>
<title>ACS Nano</title>
<title-short>ACS Nano</title-short>
<id>http://www.zotero.org/styles/acs-nano</id>
<link href="http://www.zotero.org/styles/acs-nano" rel="self"/>
<link href="http://www.zotero.org/styles/american-chemical-society-with-titles" rel="template"/>
<link href="http://pubs.acs.org/paragonplus/submission/ancac3/ancac3_authguide.pdf" rel="documentation"/>
<category citation-format="numeric"/>
<category field="chemistry"/>
<issn>1936-0851</issn>
<eissn>1936-086X</eissn>
<summary>ACS style with et al in italics</summary>
<updated>2014-09-21T00:39: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>
<macro name="editor">
<names variable="editor">
<name sort-separator=", " initialize-with=". " name-as-sort-order="all" delimiter="; " delimiter-precedes-last="always"/>
<et-al font-style="italic"/>
<label form="short" prefix=", " text-case="capitalize-first"/>
</names>
</macro>
<macro name="author">
<names variable="author" suffix=".">
<name sort-separator=", " initialize-with=". " name-as-sort-order="all" delimiter="; " delimiter-precedes-last="always"/>
<et-al font-style="italic"/>
<label form="short" prefix=", " text-case="capitalize-first"/>
</names>
</macro>
<macro name="publisher">
<group delimiter=": ">
<text variable="publisher"/>
<text variable="publisher-place"/>
</group>
</macro>
<macro name="title">
<choose>
<if type="bill book graphic legal_case legislation motion_picture report song" match="any">
<text variable="title" text-case="title" font-style="italic"/>
</if>
<else>
<text variable="title" text-case="title"/>
</else>
</choose>
</macro>
<macro name="volume">
<group delimiter=" ">
<text term="volume" form="short" text-case="capitalize-first"/>
<text variable="volume"/>
</group>
</macro>
<macro name="series">
<text variable="collection-title"/>
</macro>
<macro name="pages">
<label variable="page" form="short" suffix=" "/>
<text variable="page"/>
</macro>
<macro name="book-container">
<group delimiter=" ">
<text macro="title" suffix="."/>
<text term="in" text-case="capitalize-first"/>
<text variable="container-title" font-style="italic"/>
</group>
</macro>
<macro name="issued">
<date variable="issued" delimiter=" ">
<date-part name="year"/>
</date>
</macro>
<macro name="full-issued">
<date variable="issued" delimiter=" ">
<date-part name="month" form="long" suffix=" "/>
<date-part name="day" suffix=", "/>
<date-part name="year"/>
</date>
</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" suffix="."/>
</else>
</choose>
</macro>
<citation collapse="citation-number">
<sort>
<key variable="citation-number"/>
</sort>
<layout delimiter="," vertical-align="sup">
<text variable="citation-number"/>
</layout>
</citation>
<bibliography second-field-align="flush" entry-spacing="0" et-al-min="11" et-al-use-first="10">
<layout suffix=".">
<text variable="citation-number" prefix="(" suffix=") "/>
<text macro="author" suffix=" "/>
<choose>
<if type="article-magazine">
<group delimiter=" ">
<text macro="title" suffix="."/>
<text variable="container-title" font-style="italic" suffix="."/>
<text macro="edition"/>
<text macro="publisher"/>
<text macro="full-issued" suffix=","/>
<text macro="pages"/>
</group>
</if>
<else-if type="thesis">
<group delimiter=", ">
<group delimiter=". ">
<text macro="title"/>
<text variable="genre"/>
</group>
<text macro="publisher"/>
<text macro="issued"/>
<text macro="volume"/>
<text macro="pages"/>
</group>
</else-if>
<else-if type="bill book graphic legal_case legislation motion_picture report song" match="any">
<group delimiter="; ">
<text macro="title"/>
<text macro="editor" prefix=" "/>
<text macro="series"/>
<text macro="edition"/>
<choose>
<if type="report">
<group delimiter=" ">
<text variable="genre"/>
<text variable="number"/>
</group>
</if>
</choose>
<group delimiter=", ">
<text macro="publisher"/>
<text macro="issued"/>
</group>
<group delimiter=", ">
<text macro="volume"/>
<text macro="pages"/>
</group>
</group>
</else-if>
<else-if type="patent">
<group delimiter=", ">
<group delimiter=". ">
<text macro="title"/>
<text variable="number"/>
</group>
<date variable="issued" form="text"/>
</group>
</else-if>
<else-if type="chapter paper-conference" match="any">
<group delimiter="; ">
<text macro="book-container"/>
<text macro="editor"/>
<text macro="series"/>
<group delimiter=", ">
<text macro="publisher"/>
<text macro="issued"/>
</group>
<group delimiter=", ">
<text macro="volume"/>
<text macro="pages"/>
</group>
</group>
</else-if>
<else-if type="webpage">
<group delimiter=" ">
<text variable="title"/>
<text variable="URL"/>
<date variable="accessed" prefix="(accessed " suffix=")" delimiter=" ">
<date-part name="month" form="short" strip-periods="true"/>
<date-part name="day" suffix=", "/>
<date-part name="year"/>
</date>
</group>
</else-if>
<else-if type="article-journal">
<group delimiter=" ">
<text macro="title" suffix="."/>
<text variable="container-title" font-style="italic" form="short"/>
<group delimiter=", ">
<text macro="issued" font-weight="bold"/>
<text variable="volume" font-style="italic"/>
<text variable="page"/>
</group>
</group>
</else-if>
<else>
<group delimiter=", ">
<group delimiter=". ">
<text macro="title"/>
<text variable="container-title" font-style="italic"/>
</group>
<group delimiter=", ">
<text macro="issued"/>
<text variable="volume" font-style="italic"/>
<text variable="page"/>
</group>
</group>
</else>
</choose>
</layout>
</bibliography>
</style>

View File

@@ -1,92 +0,0 @@
;;; author-year.el --- Citation Style Lisp - the other CSL
;;; Commentary:
;;
;;; Code:
(setq citation-style
'((label . orcp-citation-author-year-label)
(prefix . "(")
(suffix . ")")
(delimiter . "; ")
(citeauthor . ((vertical-align . baseline)
(label . orcp-citation-author-label)
(prefix . "")
(suffix . " ")))
(citeyear . ((vertical-align . baseline)
(label . orcp-citation-year-label)
(prefix . "")
(suffix . " ")
(chomp-leading-space . nil)
))))
(setq bibliography-style
'((sort . nil)
(hanging-indent . 3)
(justification . full)
(spacing . 1)
(label . orcp-citation-author-year-label)
(label-prefix . "(")
(label-suffix . ") ")
(header . ((text . "Bibliography")
(font-style . bold)))
;; Formatting of fields
;; Single author name
(author . ((initialize . t) ; use initials, not full names
;; use firstname and lastname symbols
(name-order . (firstname lastname))
(name-separator . " ")
(et-al . 4) ; after 4 authors use et-al
(delimiter . "; ")
(last-author-delimiter . " and ")
(suffix . "")
(field-separator . ", ")
;; ; function to convert (first von last jr) to a string.)
(name-format . ''format-author-name)
(field-separator ", ")))
(title . ((font-style . italics)
(suffix . "")
(field-separator . ", ")))
(booktitle . ((font-style . italics)
(suffix . "")
(field-separator . "in ")))
(journal . ((suffix . "")
(field-separator . ", ")))
;; here we use some logic to group volume(issue) or volume
(volume . ((suffix . (when (orcp-get-entry-field "number" entry)
(orcp-issue entry)))
(field-separator . ", ")))
(issue . ((font-style . bold)
(prefix . "(")
(suffix . ")")
(field-separator . ", ")))
(pages . ((prefix . "pp. ")
(suffix . "")
(field-separator . " ")
(collapse-range . nil)))
(year . ((prefix . "(")
(suffix . ")")
(field-separator . ".")))
(doi . ((prefix . " ")
(suffix . ".")
(field-separator . "")
(formatter . orcp-doi-formatter)))
;; Formatting of entries
(entries . ((article . (author title journal volume pages year doi))
(inproceedings . (author title booktitle year))
(book . (author title year))
(manual . (author title url doi))
(misc . (author title url doi))
(techreport . (author title institution year))
(mastersthesis . (author title school year))
(phdthesis . (author title school year))
(t . (author title year))))))
(provide 'author-year)
;;; author-year.el ends here

View File

@@ -1,86 +0,0 @@
;;; unsrt-footnote.el --- Citation Style Lisp - the other CSL
;;; Commentary:
;; Convert citations to org-mode footnotes
;;; Code:
(setq citation-style
'((label . orcp-footnote-label)
(prefix . "")
(suffix . "")
;; sort on increasing citation numbers.
(sort . (lambda (key1 key2)
(let ((i1 (-find-index
(lambda (entry)
(string= key1 (car entry)))
*orcp-unique-entries*))
(i2 (-find-index
(lambda (entry)
(string= key2 (car entry)))
*orcp-unique-entries*)))
(> i2 i1))))
(delimiter . ", ")
(vertical-align . baseline)))
(setq bibliography-style
'((sort . nil)
(hanging-indent . 3)
(justification . full)
(spacing . 1)
(label . orcp-footnote-label)
(label-prefix . "")
(label-suffix . " ")
(header . ((text . "Bibliography")
(font-style . bold)))
;; Formatting of fields
;; Single author name
(author . ((initialize . t) ; use initials, not full names
(name-order . (lastname firstname))
(name-separator . ", ")
(et-al . 4) ; after 4 authors use et-al
(delimiter . "; ")
(last-author-delimiter . " and ")
(suffix . "")
(field-separator . ", ")
;; ; function to convert (first von last jr) to a string.)
(name-format . ''format-author-name)
(field-separator ", ")))
(title . ((font-style . italics)
(suffix . "")
(field-separator . ", ")))
(journal . ((suffix . "")
(field-separator . ", ")))
;; here we use some logic to group volume(issue) or volume
(volume . ((suffix . (when (orcp-get-entry-field "number" entry)
(orcp-issue entry)))
(field-separator . ", ")))
(issue . ((font-style . bold)
(prefix . "(")
(suffix . ")")
(field-separator . ", ")))
(pages . ((prefix . "pp. ")
(suffix . "")
(field-separator . " ")
(collapse-range . nil)))
(year . ((prefix . "(")
(suffix . ")")
(field-separator . ".")))
(doi . ((prefix . " ")
(suffix . ".")
(field-separator . "")
(formatter . orcp-doi-formatter)))
;; Formatting of entries
(entries . ((article . (author title journal volume pages year doi))
(book . (author title year))
(misc . (author title url doi))
(techreport . (author title institution year))
(mastersthesis . (author title school year))
(phdthesis . (author title school year))
(t . (author title year))))))
(provide 'unsrt)
;;; unsrt.el ends here

View File

@@ -1,107 +0,0 @@
;;; unsrt-paren.el --- numbered citations in ()
;;; Commentary:
;; This does not work well for brackets because org-mode interprets them as
;; footnotes.
;;; Code:
(setq citation-style
'((label . orcp-citation-number-label)
(prefix . "(")
(suffix . ")")
(chomp-leading-space . nil)
(chomp-trailing-space . nil)
;; sort on increasing citation numbers.
(sort . (lambda (key1 key2)
(let ((i1 (-find-index
(lambda (entry)
(string= key1 (car entry)))
*orcp-unique-entries*))
(i2 (-find-index
(lambda (entry)
(string= key2 (car entry)))
*orcp-unique-entries*)))
(> i2 i1))))
(collapse . 'orcp-collapse-numeric-range)
(delimiter . ",")
(vertical-align . baseline)
(transpose-punctuation . nil) ;put citations on right of punctuation
(citenum . ((vertical-align . baseline)
(prefix . "")
(suffix . "")
(chomp-leading-space . nil)
(chomp-trailing-space . nil)))
(citeauthor . ((vertical-align . baseline)
(label . orcp-citation-author-label)
(prefix . "")
(suffix . "")
(chomp-leading-space . nil)
(chomp-trailing-space . nil)))
(citeyear . ((vertical-align . baseline)
(label . orcp-citation-year-label)
(prefix . "")
(suffix . "")
(chomp-leading-space . nil)
(chomp-trailing-space . nil)))))
(setq bibliography-style
'((sort . nil)
(hanging-indent . 3)
(justification . full)
(spacing . 1)
(label . orcp-citation-number-label)
(label-prefix . "")
(label-suffix . ") ")
(header . ((text . "Bibliography")
(font-style . bold)))
;; Formatting of fields
;; Single author name
(author . ((initialize . t) ; use initials, not full names
(name-order . (lastname firstname))
(name-separator . ", ")
(et-al . 4) ; after 4 authors use et-al
(delimiter . "; ")
(last-author-delimiter . " and ")
(suffix . "")
(field-separator . ", ")
;; ; function to convert (first von last jr) to a string.)
(name-format . ''format-author-name)
(field-separator ", ")))
(title . ((font-style . italics)
(suffix . "")
(field-separator . ", ")))
(journal . ((suffix . "")
(field-separator . ", ")))
;; here we use some logic to group volume(issue) or volume
(volume . ((suffix . (when (orcp-get-entry-field "number" entry)
(orcp-issue entry)))
(field-separator . ", ")))
(issue . ((font-style . bold)
(prefix . "(")
(suffix . ")")
(field-separator . ", ")))
(pages . ((prefix . "pp. ")
(suffix . "")
(field-separator . " ")
(collapse-range . nil)))
(year . ((prefix . "(")
(suffix . ")")
(field-separator . ".")))
(doi . ((prefix . " ")
(suffix . ".")
(field-separator . "")
(formatter . orcp-doi-formatter)))
;; Formatting of entries
(entries . ((article . (author title journal volume pages year doi))
(book . (author title year))
(misc . (author title url doi))
(techreport . (author title institution year))
(mastersthesis . (author title school year))
(phdthesis . (author title school year))
(t . (author title year))))))
(provide 'unsrt-paren)
;;; unsrt-paren.el ends here

View File

@@ -1,111 +0,0 @@
;;; unsrt.el --- Citation Style Lisp - the other CSL
;;; Commentary:
;;
;;; Code:
(setq citation-style
'((label . orcp-citation-number-label)
(prefix . "")
(suffix . "")
(chomp-leading-space . t)
(chomp-trailing-space . nil)
;; sort on increasing citation numbers.
(sort . (lambda (key1 key2)
(let ((i1 (-find-index
(lambda (entry)
(string= key1 (car entry)))
*orcp-unique-entries*))
(i2 (-find-index
(lambda (entry)
(string= key2 (car entry)))
*orcp-unique-entries*)))
(> i2 i1))))
(collapse . 'orcp-collapse-numeric-range)
(delimiter . ",")
(vertical-align . superscript)
(transpose-punctuation . t) ;put citations on right of punctuation
(citenum . ((vertical-align . baseline)
(prefix . " ")
(suffix . " ")
(chomp-leading-space . nil)
(chomp-trailing-space . nil)))
(citeauthor . ((vertical-align . baseline)
(label . orcp-citation-author-label)
(prefix . "")
(suffix . " ")
(chomp-leading-space . nil)
(chomp-trailing-space . nil)))
(citeyear . ((vertical-align . baseline)
(label . orcp-citation-year-label)
(prefix . "")
(suffix . " ")
(chomp-leading-space . nil)
(chomp-trailing-space . nil)))))
(setq bibliography-style
'((sort . nil)
(hanging-indent . 3)
(justification . full)
(spacing . 1)
(label . orcp-citation-number-label)
(label-prefix . "")
(label-suffix . ". ")
(header . ((text . "Bibliography")
(font-style . bold)))
;; Formatting of fields
;; Single author name
(author . ((initialize . t) ; use initials, not full names
(name-order . (lastname firstname))
(name-separator . ", ")
(et-al . 4) ; after 4 authors use et-al
(delimiter . "; ")
(last-author-delimiter . " and ")
(suffix . "")
(field-separator . ", ")
;; ; function to convert (first von last jr) to a string.)
(name-format . ''format-author-name)
(field-separator ", ")))
(title . ((font-style . italics)
(suffix . "")
(field-separator . ", ")))
(booktitle . ((font-style . italics)
(suffix . "")
(field-separator . "in ")))
(journal . ((suffix . "")
(field-separator . ", ")))
;; here we use some logic to group volume(issue) or volume
(volume . ((suffix . (when (orcp-get-entry-field "number" entry)
(orcp-issue entry)))
(field-separator . ", ")))
(issue . ((font-style . bold)
(prefix . "(")
(suffix . ")")
(field-separator . ", ")))
(pages . ((prefix . "pp. ")
(suffix . "")
(field-separator . " ")
(collapse-range . nil)))
(year . ((prefix . "(")
(suffix . ")")
(field-separator . ".")))
(doi . ((prefix . " ")
(suffix . ".")
(field-separator . "")
(formatter . orcp-doi-formatter)))
;; Formatting of entries
(entries . ((article . (author title journal volume pages year doi))
(inproceedings . (author title booktitle year))
(book . (author title year))
(misc . (author title url doi))
(techreport . (author title institution year))
(mastersthesis . (author title school year))
(phdthesis . (author title school year))
(t . (author title year))))))
(provide 'unsrt)
;;; unsrt.el ends here

View File

@@ -1,92 +0,0 @@
* DONE Introduction to a citation processor in org-ref
CLOSED: [2015-12-11 Fri 18:05]
:PROPERTIES:
:categories: emacs,orgref,orgmode,citations
:date: 2015/12/11 18:05:43
:updated: 2015/12/11 18:22:40
:END:
As a potential solution for citions in org-mode for non-LaTeX export, here we introduce csl (citation syntax lisp). The idea is heavily influenced by the xml-based Citation Syntax Language, but uses lisp sexps instead.
Briefly, there is a csl file that contains two variables: citation-style and bibliography-style. The citation-style defines how the in-text citations are represented for different types of citations. The bibliography-style defines how the bibliography is constructed.
What do we gain by this?
1. No need for external citeproc program, and hackability by org-mode experts.
2. Punctuation transposition and space chomping, i.e. put superscripts on the right side of punctuation if you want it, and remove whitespace before superscripts if you want it.
3. Total tunability of the citation format to different backends.
4. Easy to change bibliography format with the bibliographystyle link.
5. The use of Bibtex databases. These are plain text, and flexible.
The real code for this is too long to blog about. Instead, you should check it out here: https://github.com/jkitchin/org-ref/tree/master/citeproc
** Reference types
- A book cite:kittel-2005-introd-solid.
- An article cite:kitchin-2015-examp
- A miscellaneous bibtex type cite:xu-suppor.
There is work to do in supporting other types of entry types that are common in bibtex files.
** Citation types
- Regular citation: cite:kitchin-2015-examp
- citenum: See Ref. citenum:kitchin-2015-examp
- citeauthor: citeauthor:kitchin-2015-examp
- citeyear: citeyear:kitchin-2015-examp
There is work to do in supporting other types of citations.
** Multiple citations and sorting within citation
You can specify that the cites within a citation are consistently sorted in the export.
- a,b: cite:kitchin-2015-examp,kitchin-2015-data-surfac-scien
- b,a: cite:kitchin-2015-data-surfac-scien,kitchin-2015-examp
There is work to do for range collapsing, e.g. to turn 1,2,3 into 1-3.
** Space chomping and punctuation testing
I think citations should always be put in the sentence they logically belong to. LaTeX has a feature through natbib I think where for some styles, e.g. superscripts, the citations are moved to the right side of punctuation, and whitespace is chomped so the superscript is next to words, not separated by spaces. We can do that here too.
- Citation at end of sentence cite:kitchin-2015-examp.
- Citation in clause cite:kitchin-2015-examp,kitchin-2015-data-surfac-scien, with a comma.
- Citation in middle of cite:kitchin-2015-examp,kitchin-2015-data-surfac-scien a sentence.
** Building
:PROPERTIES:
:date: 2015/12/11 14:47:59
:updated: 2015/12/11 14:48:26
:END:
At the moment, you have to add a hook function to put the replacements in the document before parsing.
#+BEGIN_SRC emacs-lisp
(add-to-list 'load-path ".")
(require 'org-ref-citeproc)
(let ((org-export-before-parsing-hook '(orcp-citeproc)))
(browse-url (org-html-export-to-html)))
#+End_src
#+RESULTS:
: #<process open ./readme-author-year.html>
** Summary thoughts
This looks promising. There is probably a lot of work to do to make this as robust as say citeproc-js or the Zotero handler. I am not sure if we could write this in a way to directly use the CSL. My feeling is it would not be as flexible as this, and we would have to add to it anyway.
Here are some remaining things that could be worked on if we continue this direction.
1. Other bibtex entries need to be tested out.
2. Remaining bibtex fields need to be defined.
3. Standardization of styling that can be done. Not all features described in my csl are supported, e.g. et. al. and probably others.
4. The author-year style needs name disambiguation somehow.
5. Hyperlinking in html.
6. Make sure export to other backends works.
7. Can this work for notes-based styles?
** Bibliography
You use a bibliographystyle link to specify a csl. These are similar to bibtex styles, and in some cases no change is needed for LaTeX export (although you may have to remove the citeproc hook function).
bibliographystyle:author-year
bibliography:~/Dropbox/bibliography/references.bib

View File

@@ -1,93 +0,0 @@
* DONE Introduction to a citation processor in org-ref
CLOSED: [2015-12-11 Fri 18:05]
:PROPERTIES:
:categories: emacs,orgref,orgmode,citations
:date: 2015/12/11 18:05:43
:updated: 2015/12/11 18:22:40
:END:
As a potential solution for citions in org-mode for non-LaTeX export, here we introduce csl (citation syntax lisp). The idea is heavily influenced by the xml-based Citation Syntax Language, but uses lisp sexps instead.
Briefly, there is a csl file that contains two variables: citation-style and bibliography-style. The citation-style defines how the in-text citations are represented for different types of citations. The bibliography-style defines how the bibliography is constructed.
What do we gain by this?
1. No need for external citeproc program, and hackability by org-mode experts.
2. Punctuation transposition and space chomping, i.e. put superscripts on the right side of punctuation if you want it, and remove whitespace before superscripts if you want it.
3. Total tunability of the citation format to different backends.
4. Easy to change bibliography format with the bibliographystyle link.
5. The use of Bibtex databases. These are plain text, and flexible.
The real code for this is too long to blog about. Instead, you should check it out here: https://github.com/jkitchin/org-ref/tree/master/citeproc
** Reference types
- A book cite:kittel-2005-introd-solid.
- An article cite:kitchin-2015-examp
- A miscellaneous bibtex type cite:xu-suppor.
There is work to do in supporting other types of entry types that are common in bibtex files.
** Citation types
- Regular citation: cite:kitchin-2015-examp
- citenum: See Ref. citenum:kitchin-2015-examp
- citeauthor: citeauthor:kitchin-2015-examp
- citeyear: citeyear:kitchin-2015-examp
There is work to do in supporting other types of citations.
** Multiple citations and sorting within citation
You can specify that the cites within a citation are consistently sorted in the export.
- a,b: cite:kitchin-2015-examp,kitchin-2015-data-surfac-scien
- b,a: cite:kitchin-2015-data-surfac-scien,kitchin-2015-examp
There is work to do for range collapsing, e.g. to turn 1,2,3 into 1-3.
** Space chomping and punctuation testing
I think citations should always be put in the sentence they logically belong to. LaTeX has a feature through natbib I think where for some styles, e.g. superscripts, the citations are moved to the right side of punctuation, and whitespace is chomped so the superscript is next to words, not separated by spaces. We can do that here too.
- Citation at end of sentence cite:kitchin-2015-examp.
- Citation in clause cite:kitchin-2015-examp,kitchin-2015-data-surfac-scien, with a comma.
- Citation in middle of cite:kitchin-2015-examp,kitchin-2015-data-surfac-scien a sentence.
** Building
:PROPERTIES:
:date: 2015/12/11 14:47:59
:updated: 2015/12/11 14:48:26
:END:
At the moment, you have to add a hook function to put the replacements in the document before parsing.
#+BEGIN_SRC emacs-lisp
(add-to-list 'load-path ".")
(require 'org-ref-citeproc)
(when (file-exists-p "readme.html") (delete-file "readme.html"))
(let ((org-export-before-parsing-hook '(orcp-citeproc)))
(browse-url (org-html-export-to-html)))
#+End_src
#+RESULTS:
: #<process open ./readme-unsrt.html>
** Summary thoughts
This looks promising. There is probably a lot of work to do to make this as robust as say citeproc-js or the Zotero handler. I am not sure if we could write this in a way to directly use the CSL. My feeling is it would not be as flexible as this, and we would have to add to it anyway.
Here are some remaining things that could be worked on if we continue this direction.
1. Other bibtex entries need to be tested out.
2. Remaining bibtex fields need to be defined.
3. Standardization of styling that can be done. Not all features described in my csl are supported, e.g. et. al. and probably others.
4. The author-year style needs name disambiguation somehow.
5. Hyperlinking in html.
6. Make sure export to other backends works.
7. Can this work for notes-based styles?
** Bibliography
You use a bibliographystyle link to specify a csl. These are similar to bibtex styles, and in some cases no change is needed for LaTeX export (although you may have to remove the citeproc hook function).
bibliographystyle:unsrt
bibliography:~/Dropbox/bibliography/references.bib

View File

@@ -1,203 +0,0 @@
@techreport{2011-mater-genom,
title = {Materials Genome Initiative for Global Competitiveness},
institution = {National Science and Technology Council},
year = {2011},
type = {Report}
}
@phdthesis{Hossein-thesis,
author = {Hossein Pourmatin},
title = {Computational Multiscale Methods for Defects: 1. Line Defects
in Liquid Crystals; 2. Electron Scattering in Defected
Crystals},
school = {Carnegie Mellon University},
year = 2014,
note = {Available at
\url{sites.google.com/site/kaushikdayal/publications#Theses}}
}
@inproceedings{abolhasani-2011-model,
Author = {Abolhasani, M. and Kumacheva, E. and G{\"u}nther,
A.},
Title = {Model-predictive Strategy for Exploration of Carbon
Dioxide Dissolution and Mass Transfer},
Booktitle = {15th International Conference on Miniaturized
Systems for Chemistry and Life Sciences},
Year = 2011,
Month = {October},
Url =
{"http://www.rsc.org/images/LOC/2011/PDFs/Papers/224_1180.pdf}
}
@article{anderson-1977-raman,
author = {George R. Anderson},
title = {The {R}aman Spectra of Carbon Dioxide in Liquid Water and
Water-D2},
journal = {J. Phys. Chem.},
volume = 81,
number = 3,
pages = {273-276},
year = 1977,
doi = {10.1021/j100518a017},
url = {http://dx.doi.org/10.1021/j100518a017},
month = 2,
eprint = {http://pubs.acs.org/doi/pdf/10.1021/j100518a017},
}
@MastersThesis{ding-2012-metal-oxide,
author = {Zhizhong Ding},
title = {Metal Oxide Oxygen Carriers for Chemical-Looping Combustion},
school = {Carnegie Mellon University},
year = 2012}
@article{kitchin-2015-data-surfac-scien,
author = "John R. Kitchin",
title = {Data Sharing in Surface Science},
journal = "Surface Science ",
volume = "N/A",
pages = "in press",
year = 2015,
doi = {10.1016/j.susc.2015.05.007},
url =
"http://www.sciencedirect.com/science/article/pii/S0039602815001326",
issn = "0039-6028",
keywords = {DESC0004031, early-career, orgmode, Data sharing },
}
@article{kitchin-2015-examp,
author = {Kitchin, John R.},
title = {Examples of Effective Data Sharing in Scientific Publishing},
journal = {ACS Catalysis},
volume = {5},
number = {6},
pages = {3894-3899},
year = 2015,
doi = {10.1021/acscatal.5b00538},
url = { http://dx.doi.org/10.1021/acscatal.5b00538 },
keywords = {DESC0004031, early-career, orgmode, Data sharing },
eprint = { http://dx.doi.org/10.1021/acscatal.5b00538 },
}
@book{kittel-2005-introd-solid,
author = {Charles Kittel},
title = {Introduction to Solid State Physics},
publisher = {Wiley},
year = 2005,
edition = {8th}
}
@misc{xu-suppor,
author = {Zhongnan Xu and Jan Rossmeisl and John R. Kitchin},
title = {Supporting data for: A linear response, {DFT+U} study of trends
in the oxygen evolution activity of transition metal rutile
dioxides. doi:10.5281/zenodo.12635},
keywords = {DESC0004031, early-career, },
year = {2015},
url = {https://zenodo.org/record/12635},
doi = {10.5281/zenodo.12635}
}
@article{ye-2012-proces-charac,
author = {Y. E. Chunbo and Guangwen CHEN and Quan YUAN},
title = {Process Characteristics of \ce{CO2} Absorption By Aqueous
Monoethanolamine in a Microchannel Reactor},
journal = {Chinese Journal of Chemical Engineering},
volume = 20,
number = 1,
pages = {111-119},
year = 2012,
doi = {10.1016/s1004-9541(12)60370-x},
url = {http://dx.doi.org/10.1016/S1004-9541(12)60370-X},
}
@article{yeo-2012-in-situ,
author = {Yeo, Boon Siang and Bell, Alexis T.},
title = {In Situ {R}aman Study of Nickel Oxide and Gold-Supported
Nickel Oxide Catalysts for the Electrochemical Evolution of
Oxygen},
journal = {The Journal of Physical Chemistry C},
volume = 116,
number = 15,
pages = {8394-8400},
year = 2012,
doi = {10.1021/jp3007415},
url = {http://pubs.acs.org/doi/abs/10.1021/jp3007415},
eprint = {http://pubs.acs.org/doi/pdf/10.1021/jp3007415},
}
@article{zhu-2013-sulfur,
author = {Zhu, Qingjun and Wegener, Staci L. and Xie, Chao and Uche,
Obioma and Neurock, Matthew and Marks, Tobin J.},
title = {Sulfur As a Selective "soft" Oxidant for Catalytic Methane
Conversion Probed By Experiment and Theory},
journal = {Nature chemistry},
volume = 5,
pages = {104-109},
year = 2013,
doi = "10.1002/ange.201311111",
url =
"http://www.nature.com/nchem/journal/v5/n2/full/nchem.1527.html",
}
@article{lizzit-2001-surfac-ru,
author = {S. Lizzit and A. Baraldi and A. Groso and K. Reuter and M. V.
Ganduglia-Pirovano and C. Stampfl and M. Scheffler and M.
Stichler and C. Keller and W. Wurth and D. Menzel},
title = {Surface Core-Level Shifts of Clean and Oxygen-Covered
{Ru}(0001)},
journal = {Phys. Rev. B},
volume = 63,
number = 20,
pages = {205419},
year = 2001,
doi = {10.1103/physrevb.63.205419},
url = {http://dx.doi.org/10.1103/physrevb.63.205419},
date_added = {Mon Nov 16 16:28:01 2015},
}
@article{weaver-2011-high-selec,
author = {Jason F. Weaver and Can Hakanoglu and Abbin Antony and Aravind
Asthagiri},
title = {High Selectivity for Primary {C-H} Bond Cleavage of Propane
$\sigma$-complexes on the {PdO}(101) Surface},
keywords = {alkane},
journal = {J. Am. Chem. Soc.},
volume = 133,
number = 40,
pages = {16196-16200},
year = 2011,
doi = {10.1021/ja206599k},
url = {http://dx.doi.org/10.1021/ja206599k},
date_added = {Sat Nov 28 09:10:59 2015},
}
@article{antony-2012-pathw-c,
author = {Abbin Antony and Aravind Asthagiri and Jason F. Weaver},
title = {Pathways for {C-H} Bond Cleavage of Propane $\sigma$-complexes on
{PdO}(101)},
keywords = {alkane},
journal = {Phys. Chem. Chem. Phys.},
volume = 14,
number = 35,
pages = 12202,
year = 2012,
doi = {10.1039/c2cp41900a},
url = {http://dx.doi.org/10.1039/c2cp41900a},
date_added = {Sat Nov 28 09:13:32 2015},
}
@article{wang-2013-immob-co2,
author = {Xianfeng Wang and Novruz G. Akhmedov and Yuhua Duan and David
Luebke and Bingyun Li},
title = {Immobilization of Amino Acid Ionic Liquids Into Nanoporous
Microspheres As Robust Sorbents for CO2 Capture},
journal = {J. Mater. Chem. A},
volume = 1,
number = 9,
pages = 2978,
year = 2013,
doi = {10.1039/c3ta00768e},
url = {http://dx.doi.org/10.1039/C3TA00768E},
date_added = {Thu Dec 3 06:13:09 2015},
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
;;; doi-utils.el --- DOI utilities for making bibtex entries
;; Copyright (C) 2015 John Kitchin
;; Copyright (C) 2015-2021 John Kitchin
;; Author: John Kitchin <jkitchin@andrew.cmu.edu>
;; Keywords: convenience
@@ -36,17 +36,10 @@
;;; Code:
(defvar org-ref-pdf-directory)
(defvar org-ref-bibliography-notes)
(defvar org-ref-default-bibliography)
(defvar reftex-default-bibliography)
(defvar url-http-end-of-headers)
(declare-function org-ref-bib-citation "org-ref-core")
(declare-function org-ref-find-bibliography "org-ref-core")
(declare-function org-ref-clean-bibtex-entry "org-ref-core")
(declare-function reftex-get-bib-field "reftex-cite")
(declare-function bibtex-completion-edit-notes "bibtex-completion")
(declare-function helm "helm")
(declare-function org-bibtex-yank "org-bibtex")
(declare-function org-ref-possible-bibfiles "org-ref-core")
@@ -62,6 +55,7 @@
(require 'url-http)
(require 'org-ref-utils)
(require 'hydra)
;;* Customization
(defgroup doi-utils nil
@@ -82,11 +76,6 @@
:type 'boolean
:group 'doi-utils)
(defcustom doi-utils-make-notes
t
"Whether to create notes when adding bibtex entries."
:type 'boolean
:group 'doi-utils)
(defcustom doi-utils-timestamp-field
"DATE_ADDED"
@@ -102,15 +91,6 @@ e.g. (lambda () nil)"
:type 'function
:group 'doi-utils)
(defcustom doi-utils-make-notes-function
(lambda ()
(bibtex-beginning-of-entry)
(bibtex-completion-edit-notes (list (cdr (assoc "=key=" (bibtex-parse-entry))))))
"Function to create notes for a bibtex entry.
Set `doi-utils-make-notes' to nil if you want no notes."
:type 'function
:group 'doi-utils)
(defcustom doi-utils-dx-doi-org-url
"https://doi.org/"
@@ -118,12 +98,22 @@ Set `doi-utils-make-notes' to nil if you want no notes."
:type 'string
:group 'doi-utils)
(defcustom doi-utils-metadata-function 'doi-utils-get-json-metadata
"Function for retrieving json metadata from `doi-utils-dx-doi-org-url'.
The default is `doi-utils-get-json-metadata', but it sometimes
fails with a proxy. An alternative is
`doi-utils-get-json-metadata-curl' which requires an external
program to use curl.")
program to use curl."
:type 'function
:group 'doi-utils)
(defcustom doi-utils-async-download t
"Use `doi-utils-async-download-pdf' to get pdfs asynchrounously.
If nil use `doi-utils-get-bibtex-entry-pdf' synchronously."
:type 'boolean
:group 'doi-utils)
;;* Getting pdf files from a DOI
@@ -306,6 +296,15 @@ must return a pdf-url, or nil.")
(format "http://scitation.aip.org/deliver/fulltext/%s.pdf?itemId=/%s&mimeType=pdf&containerItemId=%s"
p1 p2 p3))))
(defun aip-pdf-url-2 (*doi-utils-redirect*)
"Get url to the pdf from *DOI-UTILS-REDIRECT*."
;; [2021-08-28 Sat] Seems like they changed the link a little?
;; https://aip.scitation.org/doi/10.1063/1.5019667
;; to
;; https://aip.scitation.org/doi/pdf/10.1063/1.5019667
(when (string-match "^http\\(s?\\)://aip.scitation.org" *doi-utils-redirect*)
(concat "https://aip.scitation.org/doi/pdf" (cl-second (split-string *doi-utils-redirect* "doi")))))
;;** Taylor and Francis
(defun tandfonline-pdf-url (*doi-utils-redirect*)
@@ -609,6 +608,7 @@ It would be better to parse this, but here I just use a regexp.
'iop-pdf-url
'jstor-pdf-url
'aip-pdf-url
'aip-pdf-url-2
'science-direct-pdf-url
'linkinghub-elsevier-pdf-url
'tandfonline-pdf-url
@@ -647,16 +647,82 @@ until one is found."
(throw 'pdf-url this-pdf-url))))))
;;** Finally, download the pdf
(defvar bibtex-completion-library-path)
(defvar bibtex-completion-bibliography)
(declare-function async-start "async")
;;;###autoload
(defun doi-utils-async-download-pdf ()
"Download the PDF for bibtex entry at point asynchronously.
It is not fully async, only the download is. Fully async is
harder because you need to run `doi-utils-get-pdf-url' async
too. "
(interactive)
(require 'async)
(save-excursion
(bibtex-beginning-of-entry)
(let (;; get doi, removing http://dx.doi.org/ if it is there.
(doi (replace-regexp-in-string
"https?://\\(dx.\\)?.doi.org/" ""
(bibtex-autokey-get-field "doi")))
(key (cdr (assoc "=key=" (bibtex-parse-entry))))
(pdf-url)
(pdf-file))
(setq pdf-file
(concat (cond
((stringp bibtex-completion-library-path)
bibtex-completion-library-path)
((= 1 (length bibtex-completion-library-path))
(car bibtex-completion-library-path))
(t
(completing-read "Dir: " bibtex-completion-library-path)))
key ".pdf"))
(unless doi (error "No DOI found to get a pdf for"))
(when (file-exists-p pdf-file)
(error "%s already exists. Delete to re-download" pdf-file))
;; (doi-utils-get-pdf-url "10.1063/1.5019667")
;; If you get here, try getting the pdf file
(async-start
`(lambda ()
(setq package-user-dir ,package-user-dir)
(require 'package)
(package-initialize)
(setq load-path (list ,@load-path))
(require 'doi-utils)
(setq pdf-url (doi-utils-get-pdf-url ,doi))
(when pdf-url
(url-copy-file pdf-url ,pdf-file t)
(let* ((header (with-temp-buffer
(set-buffer-multibyte nil)
(insert-file-contents-literally ,pdf-file nil 0 5)
(buffer-string)))
(valid (and (stringp header)
(string-equal (encode-coding-string header 'utf-8) "%PDF-"))))
(if valid
(format "%s downloaded" ,pdf-file)
(delete-file ,pdf-file)
(require 'browse-url)
(browse-url pdf-url)
(message "Invalid pdf (file deleted). Header = %s" header)))))
`(lambda (result)
(message "doi-utils-async-download-pdf: %s" result))))))
;;;###autoload
(defun doi-utils-get-bibtex-entry-pdf (&optional arg)
"Download pdf for entry at point if the pdf does not already exist locally.
The entry must have a doi. The pdf will be saved
to `org-ref-pdf-directory', by the name %s.pdf where %s is the
bibtex label. Files will not be overwritten. The pdf will be
checked to make sure it is a pdf, and not some html failure
page. You must have permission to access the pdf. We open the pdf
at the end if `doi-utils-open-pdf-after-download' is non-nil.
The entry must have a doi. The pdf will be saved, by the name
%s.pdf where %s is the bibtex label. Files will not be
overwritten. The pdf will be checked to make sure it is a pdf,
and not some html failure page. You must have permission to
access the pdf. We open the pdf at the end if
`doi-utils-open-pdf-after-download' is non-nil.
With one prefix ARG, directly get the pdf from a file (through
`read-file-name') instead of looking up a DOI. With a double
@@ -667,7 +733,7 @@ checked."
(interactive "P")
(save-excursion
(bibtex-beginning-of-entry)
(let ( ;; get doi, removing http://dx.doi.org/ if it is there.
(let (;; get doi, removing http://dx.doi.org/ if it is there.
(doi (replace-regexp-in-string
"https?://\\(dx.\\)?.doi.org/" ""
(bibtex-autokey-get-field "doi")))
@@ -675,11 +741,15 @@ checked."
(pdf-url)
(pdf-file))
(setq pdf-file (concat
(if org-ref-pdf-directory
(file-name-as-directory org-ref-pdf-directory)
(read-directory-name "PDF directory: " "."))
key ".pdf"))
(setq pdf-file
(concat (cond
((stringp bibtex-completion-library-path)
bibtex-completion-library-path)
((= 1 (length bibtex-completion-library-path))
(car bibtex-completion-library-path))
(t
(completing-read "Dir: " bibtex-completion-library-path)))
key ".pdf"))
;; now get file if needed.
(unless (file-exists-p pdf-file)
(cond
@@ -701,43 +771,65 @@ checked."
(write-file pdf-file)))
(t
(message "We don't have a recipe for this journal.")))
(when (file-exists-p pdf-file)
(bibtex-set-field "file" pdf-file))
(when (and doi-utils-open-pdf-after-download (file-exists-p pdf-file))
(org-open-file pdf-file))))))
;;* Getting bibtex entries from a DOI
;; I
;; [[http://homepages.see.leeds.ac.uk/~eeaol/notes/2013/02/doi-metadata/][found]]
;; you can download metadata about a DOI from http://dx.doi.org. You just have
;; to construct the right http request to get it. Here is a function that gets
;; the metadata as a plist in emacs.
;;
;;
(defvar doi-utils-cache nil
"Cache variable for storing data we can reuse.
A-list (doi . data) where doi is doi string, and data is what is
retrieved from it. This is transient, and disappears when you
restart Emacs. This mostly exists to prevent
`doi-utils-update-field' from needing to download the data for
every field.")
(defun doi-utils-clear-cache ()
"Clear `doi-utils-cache'."
(interactive)
(setq doi-utils-cache '()))
(defun doi-utils-get-json-metadata (doi)
"Try to get json metadata for DOI. Open the DOI in a browser if we do not get it."
(let ((url-request-method "GET")
(url-mime-accept-string "application/citeproc+json")
(json-object-type 'plist)
(json-data)
(url (concat doi-utils-dx-doi-org-url doi)))
(with-current-buffer
(url-retrieve-synchronously
;; (concat "http://dx.doi.org/" doi)
url)
(setq json-data (buffer-substring url-http-end-of-headers (point-max)))
(cond
((or (string-match "<title>Error: DOI Not Found</title>" json-data)
(string-match "Resource not found" json-data)
(string-match "Status *406" json-data)
(string-match "400 Bad Request" json-data))
(browse-url (concat doi-utils-dx-doi-org-url doi))
(error "Something went wrong. We got this response:
(if-let ((data (cdr (assoc doi doi-utils-cache))))
;; We have the data already, so we return it.
data
(let ((url-request-method "GET")
(url-mime-accept-string "application/citeproc+json")
(json-object-type 'plist)
(json-data)
(url (concat doi-utils-dx-doi-org-url doi)))
(with-current-buffer
(url-retrieve-synchronously
;; (concat "http://dx.doi.org/" doi)
url)
(setq json-data (buffer-substring url-http-end-of-headers (point-max)))
(when (or (string-match "<title>Error: DOI Not Found</title>" json-data)
(string-match "Resource not found" json-data)
(string-match "Status *406" json-data)
(string-match "400 Bad Request" json-data))
(browse-url (concat doi-utils-dx-doi-org-url doi))
(error "Something went wrong. We got this response:
%s
Opening %s" json-data url))
;; everything seems ok with the data
(t
(json-read-from-string json-data))))))
(setq data (json-read-from-string json-data))
(cl-pushnew (cons doi data) doi-utils-cache)
data))))
(defun doi-utils-get-json-metadata-curl (doi)
@@ -806,7 +898,9 @@ Opening %s" json-data url))
(volume (plist-get results :volume))
(issue (plist-get results :issue))
(number (plist-get results :issue))
(year (elt (elt (plist-get (plist-get results :issued) :date-parts) 0) 0))
(year (or (elt (elt (plist-get (plist-get results :issued) :date-parts) 0) 0)
(elt (elt (plist-get (plist-get results :approved) :date-parts) 0) 0)
))
;; Some dates don't have a month in them.
(month (let ((date (elt
(plist-get (plist-get results :issued) :date-parts) 0)))
@@ -817,7 +911,9 @@ Opening %s" json-data url))
(plist-get results :article-number)))
(doi (plist-get results :DOI))
(url (plist-get results :URL))
(booktitle (plist-get results :container-title))))
(booktitle (plist-get results :container-title))
(school (or (plist-get results :school)
(plist-get (plist-get results :institution) :name)))))
;; Next, we need to define the different bibtex types. Each type has a bibtex
;; type (for output) and the type as provided in the doi record. Finally, we
@@ -882,6 +978,8 @@ MATCHING-TYPES."
(doi-utils-def-bibtex-type inbook ("chapter" "book-chapter" "reference-entry")
author title booktitle series publisher year pages doi url)
(doi-utils-def-bibtex-type phdthesis ("phdthesis" "thesis" "dissertation")
author title school publisher year)
;; this is what preprints in chemrxiv look like for now
(doi-utils-def-bibtex-type misc ("posted-content")
@@ -901,12 +999,10 @@ MATCHING-TYPES."
;; That is just the string for the entry. To be useful, we need a function that
;; inserts the string into a buffer. This function will insert the string at the
;; cursor, clean the entry, try to get the pdf, and create a notes entry for
;; you.
;; cursor, clean the entry, try to get the pdf.
(defun doi-utils-insert-bibtex-entry-from-doi (doi)
"Insert bibtex entry from a DOI.
Also cleans entry using org-ref, and tries to download the corresponding pdf."
"Insert and clean bibtex entry from a DOI."
(insert (doi-utils-doi-to-bibtex-string doi))
(backward-char)
;; set date added for the record
@@ -915,31 +1011,13 @@ Also cleans entry using org-ref, and tries to download the corresponding p
(bibtex-set-field doi-utils-timestamp-field
ts)))
(org-ref-clean-bibtex-entry)
(save-buffer)
;; try to get pdf
(when doi-utils-download-pdf
(doi-utils-get-bibtex-entry-pdf))
(when (and doi-utils-make-notes org-ref-bibliography-notes)
(save-excursion
(when (f-file? org-ref-bibliography-notes)
(find-file-noselect org-ref-bibliography-notes)
(save-buffer))
(let ((bibtex-completion-bibliography (list (buffer-file-name))))
(funcall doi-utils-make-notes-function)))))
;; It may be you are in some other place when you want to add a bibtex entry.
;; This next function will open the first entry in org-ref-default-bibliography
;; go to the end, and add the entry. You can sort it later.
(save-buffer))
;;;###autoload
(defun doi-utils-add-bibtex-entry-from-doi (doi &optional bibfile)
"Add DOI entry to end of a file in the current directory.
Pick the file ending with .bib or in
`org-ref-default-bibliography'. If you have an active region that
Pick the file ending with .bib or in . If you have an active region that
starts like a DOI, that will be the initial prompt. If no region
is selected and the first entry of the kill-ring starts like a
DOI, then that is the intial prompt. Otherwise, you have to type
@@ -960,7 +1038,7 @@ Argument BIBFILE the bibliography to use."
(find-file-noselect bibfile)
;; Check if the doi already exists
(goto-char (point-min))
(if (word-search-forward (concat doi) nil t)
(if (re-search-forward (concat doi "\\_>") nil t)
(message "%s is already in this file" doi)
(goto-char (point-max))
@@ -1068,14 +1146,11 @@ Optional argument NODELIM see `bibtex-make-field'."
(insert value))))
;; The updating function for a whole entry looks like this. We get all the keys
;; from the json plist metadata, and update the fields if they exist.
(defun plist-get-keys (plist)
"Return keys in a PLIST."
(-slice plist 0 nil 2))
;;;###autoload
(defun doi-utils-update-bibtex-entry-from-doi (doi)
"Update fields in a bibtex entry from the DOI.
@@ -1235,14 +1310,15 @@ May be empty if none are found."
;;;###autoload
(defun doi-utils-open-bibtex (doi)
"Search through variable `reftex-default-bibliography' for DOI."
"Search through variable `bibtex-completion-bibliography' for DOI."
(interactive "sDOI: ")
(catch 'file
(dolist (f reftex-default-bibliography)
(find-file f)
(when (search-forward doi (point-max) t)
(bibtex-beginning-of-entry)
(throw 'file t)))))
(cl-loop for f in (if (listp bibtex-completion-bibliography)
bibtex-completion-bibliography
(list bibtex-completion-bibliography))
when (progn (find-file f)
(when (search-forward doi (point-max) t)
(bibtex-beginning-of-entry)))
return f))
;;;###autoload
@@ -1272,62 +1348,37 @@ May be empty if none are found."
"http://www.ncbi.nlm.nih.gov/pubmed/?term=%s"
(url-hexify-string doi))))
(declare-function org-element-property "org-element")
(defvar doi-link-menu-funcs '()
"Functions to run in doi menu.
Each entry is a list of (key menu-name function). The function
must take one argument, the doi.")
(setq doi-link-menu-funcs
'(("o" "pen" doi-utils-open)
("w" "os" doi-utils-wos)
("c" "iting articles" doi-utils-wos-citing)
("r" "elated articles" doi-utils-wos-related)
("a" "ds" doi-utils-ads)
("s" "Google Scholar" doi-utils-google-scholar)
("f" "CrossRef" doi-utils-crossref)
("p" "ubmed" doi-utils-pubmed)
("b" "open in bibtex" doi-utils-open-bibtex)
("g" "et bibtex entry" doi-utils-add-bibtex-entry-from-doi)))
(defhydra doi-link-follow (:color blue :hint nil)
"DOI actions:
"
("o" (doi-utils-open (org-element-property :path (org-element-context))) "open")
("w" (doi-utils-wos (org-element-property :path (org-element-context))) "wos")
("c" (doi-utils-wos-citing (org-element-property :path (org-element-context))) "wos citing articles")
("r" (doi-utils-wos-related (org-element-property :path (org-element-context))) "wos related articles" )
("a" (doi-utils-ads (org-element-property :path (org-element-context))) "ads")
("s" (doi-utils-google-scholar (org-element-property :path (org-element-context))) "Google Scholar")
("f" (doi-utils-crossref (org-element-property :path (org-element-context))) "CrossRef")
("p" (doi-utils-pubmed (org-element-property :path (org-element-context))) "Pubmed")
("b" (doi-utils-open-bibtex (org-element-property :path (org-element-context))) "open in bibtex")
("g" (doi-utils-add-bibtex-entry-from-doi (org-element-property :path (org-element-context))) "get bibtex entry"))
;;;###autoload
(defun doi-link-menu (link-string)
"Generate the link menu message, get choice and execute it.
Options are stored in `doi-link-menu-funcs'.
Argument LINK-STRING Passed in on link click."
(interactive)
(message
(concat
(mapconcat
(lambda (tup)
(concat "[" (elt tup 0) "]"
(elt tup 1) " "))
doi-link-menu-funcs "") ": "))
(let* ((input (read-char-exclusive))
(choice (assoc
(char-to-string input) doi-link-menu-funcs)))
(when choice
(funcall
(elt
choice
2)
link-string))))
(org-ref-link-set-parameters "doi"
:follow #'doi-link-menu
:export (lambda (doi desc format)
(cond
((eq format 'html)
(format "<a href=\"%s%s\">%s</a>"
doi-utils-dx-doi-org-url
doi
(or desc (concat "doi:" doi))))
((eq format 'latex)
(format "\\href{%s%s}{%s}"
doi-utils-dx-doi-org-url
doi
(or desc (concat "doi:" doi)))))))
(org-link-set-parameters "doi"
:follow (lambda (_) (doi-link-follow/body))
:export (lambda (doi desc format)
(cond
((eq format 'html)
(format "<a href=\"%s%s\">%s</a>"
doi-utils-dx-doi-org-url
doi
(or desc (concat "doi:" doi))))
((eq format 'latex)
(format "\\href{%s%s}{%s}"
doi-utils-dx-doi-org-url
doi
(or desc (concat "doi:" doi)))))))
;;* Getting a doi for a bibtex entry missing one
@@ -1360,25 +1411,21 @@ Argument LINK-STRING Passed in on link click."
;; According to http://search.crossref.org/help/api we can send a query with a
;; free form citation that may give us something back. We do this to get a list
;; of candidates, and run a helm command to get the doi.
;; of candidates, which could be used to get the doi.
(declare-function org-ref-bib-citation "org-ref-bibtex")
;;;###autoload
(defun doi-utils-crossref-citation-query ()
"Query Crossref with the title of the bibtex entry at point.
Get a list of possible matches. This opens a helm buffer to
select an entry. The default action inserts a doi and url field
in the bibtex entry at point. The second action opens the doi
url. If there is already a doi field, the function raises an
error."
Get a list of possible matches. Choose one with completion."
(interactive)
(bibtex-beginning-of-entry)
(let* ((entry (bibtex-parse-entry))
(raw-json-string)
(json-string)
(json-data)
(doi))
(unless (string= ""(reftex-get-bib-field "doi" entry))
(doi (bibtex-autokey-get-field "doi")))
(unless (string= "" doi)
(error "Entry already has a doi field"))
(with-current-buffer
@@ -1398,33 +1445,26 @@ error."
(replace-match "\\\"" nil t)))
(setq raw-json-string (buffer-substring url-http-end-of-headers (point-max)))
;; decode json string
(setq json-string (decode-coding-string (string-make-unibyte raw-json-string) 'utf-8))
(setq json-string (decode-coding-string (encode-coding-string raw-json-string 'utf-8) 'utf-8))
(setq json-data (json-read-from-string json-string)))
(let* ((name (format "Crossref hits for %s" (org-ref-bib-citation)))
(helm-candidates (mapcar (lambda (x)
(cons
(concat
(cdr (assoc 'fullCitation x)))
(cdr (assoc 'doi x))))
json-data))
(candidates (mapcar (lambda (x)
(cons
(concat
(cdr (assoc 'fullCitation x)))
(cdr (assoc 'doi x))))
json-data))
(source `((name . ,name)
(candidates . ,helm-candidates)
;; just return the candidate
(action . (("Insert doi and url field" . (lambda (doi)
(bibtex-make-field "doi" t)
(backward-char)
;; crossref returns doi url, but I prefer only a doi for the doi field
(insert (replace-regexp-in-string "^https?://\\(dx.\\)?doi.org/" "" doi))
(when (string= ""(reftex-get-bib-field "url" entry))
(bibtex-make-field "url" t)
(backward-char)
(insert doi))))
("Open url" . (lambda (doi)
(browse-url doi))))))))
(helm :sources source
:buffer "*doi utils*"))))
(doi (cdr (assoc (completing-read "DOI: " candidates) candidates))))
(bibtex-make-field "doi" t)
(backward-char)
;; crossref returns doi url, but I prefer only a doi for the doi field
(insert (replace-regexp-in-string "^https?://\\(dx.\\)?doi.org/" "" doi))
(when (string= "" (bibtex-autokey-get-field "url"))
(bibtex-make-field "url" t)
(backward-char)
(insert doi)))))
@@ -1471,14 +1511,14 @@ error."
;;* Adding a bibtex entry from a crossref query
;; The idea here is to perform a query on Crossref, get a helm buffer of
;; The idea here is to perform a query on Crossref, get a completion buffer of
;; candidates, and select the entry(ies) you want to add to your bibtex file.
;; You can select a region, e.g. a free form citation, or set of words, or you
;; can type the query in by hand.
;;;###autoload
(defun doi-utils-add-entry-from-crossref-query (query bibtex-file)
"Search Crossref with QUERY and use helm to select an entry to add to BIBTEX-FILE."
"Search Crossref with QUERY and use completion to select an entry to add to BIBTEX-FILE."
(interactive (list
(read-string
"Query: "
@@ -1495,7 +1535,7 @@ error."
(completing-read
"Bibfile: "
(append (f-entries "." (lambda (f) (f-ext? f "bib")))
org-ref-default-bibliography))))
bibtex-completion-bibliography))))
(let* ((raw-json-string)
(json-string)
(json-data)
@@ -1519,33 +1559,24 @@ error."
(replace-match "\\\"" nil t)))
(setq raw-json-string (buffer-substring url-http-end-of-headers (point-max)))
;; decode json string
(setq json-string (decode-coding-string (string-make-unibyte raw-json-string) 'utf-8))
(setq json-string (decode-coding-string (encode-coding-string raw-json-string 'utf-8) 'utf-8))
(setq json-data (json-read-from-string json-string)))
(let* ((name (format "Crossref hits for %s"
;; remove carriage returns. they cause problems in helm.
;; remove carriage returns. They can make completion confusing.
(replace-regexp-in-string "\n" " " query)))
(helm-candidates (mapcar (lambda (x)
(cons
(concat
(cdr (assoc 'fullCitation x)))
(cdr (assoc 'doi x))))
json-data))
(source `((name . ,name)
(candidates . ,helm-candidates)
;; just return the candidate
(action . (("Insert bibtex entry" . (lambda (doi)
(with-current-buffer (find-file-noselect bibtex-file)
(cl-loop for doi in (helm-marked-candidates)
do
(doi-utils-add-bibtex-entry-from-doi
(replace-regexp-in-string
"^https?://\\(dx.\\)?doi.org/" "" doi)
,bibtex-file)))))
("Open url" . (lambda (doi)
(browse-url doi))))))))
(helm :sources source
:buffer "*doi utils*"))))
(candidates (mapcar (lambda (x)
(cons
(concat
(cdr (assoc 'fullCitation x)))
(cdr (assoc 'doi x))))
json-data))
(doi (cdr (assoc (completing-read "Choice: " candidates) candidates))))
(with-current-buffer (find-file-noselect bibtex-file)
(doi-utils-add-bibtex-entry-from-doi
(replace-regexp-in-string
"^https?://\\(dx.\\)?doi.org/" "" doi)
bibtex-file)))))
(defalias 'crossref-add-bibtex-entry 'doi-utils-add-entry-from-crossref-query
"Alias function for convenience.")

View File

@@ -29,13 +29,13 @@
(url-hexify-string name)
"&Units=SI")))
(org-ref-link-set-parameters "nist-wb-name"
:follow (lambda (name)
(nist-webbook-name name)))
(org-link-set-parameters "nist-wb-name"
:follow (lambda (name)
(nist-webbook-name name)))
(org-ref-link-set-parameters "nist-wb-formula"
:follow (lambda (formula)
(nist-webbook-formula formula)))
(org-link-set-parameters "nist-wb-formula"
:follow (lambda (formula)
(nist-webbook-formula formula)))
(provide 'nist-webbook)

View File

@@ -1,6 +1,6 @@
;;; org-ref-arxiv.el --- arxiv utilities for org-mode -*- lexical-binding: t; -*-
;; Copyright (C) 2015 John Kitchin
;; Copyright (C) 2015-2021 John Kitchin
;; Author: John Kitchin <jkitchin@andrew.cmu.edu>
;; Keywords:
@@ -33,12 +33,12 @@
(require 'org-ref-utils)
(require 'parsebib)
(require 'xml)
;; This is a local variable defined in `url-http'. We need it to avoid
;; byte-compiler errors.
(defvar url-http-end-of-headers)
(defvar org-ref-default-bibliography)
(defvar org-ref-pdf-directory)
(declare-function parsebib-find-bibtex-dialect "parsebib")
(declare-function org-ref-clean-bibtex-entry "org-ref-core")
@@ -48,17 +48,17 @@
;;* The org-mode link
;; this just makes a clickable link that opens the entry.
;; example: arxiv:cond-mat/0410285
(org-ref-link-set-parameters "arxiv"
:follow (lambda (link-string)
(browse-url (format "http://arxiv.org/abs/%s" link-string)))
:export (lambda (keyword desc format)
(cond
((eq format 'html)
(format "<a href=\"http://arxiv.org/abs/%s\">arxiv:%s</a>"
keyword (or desc keyword)))
((eq format 'latex)
;; write out the latex command
(format "\\url{http://arxiv.org/abs/%s}{%s}" keyword (or desc keyword))))))
(org-link-set-parameters "arxiv"
:follow (lambda (link-string)
(browse-url (format "http://arxiv.org/abs/%s" link-string)))
:export (lambda (keyword desc format)
(cond
((eq format 'html)
(format "<a href=\"http://arxiv.org/abs/%s\">arxiv:%s</a>"
keyword (or desc keyword)))
((eq format 'latex)
;; write out the latex command
(format "\\url{http://arxiv.org/abs/%s}{%s}" keyword (or desc keyword))))))
;;* Getting a bibtex entry for an arXiv article using remote service:
;; For an arxiv article, there is a link to a NASA ADS page like this:
@@ -76,23 +76,18 @@
(concat
"http://adsabs.harvard.edu/cgi-bin/bib_query?arXiv:"
arxiv-number))
(search-forward-regexp "name=\\\"bibcode\\\" value=\\\"\\(.*\\)\\\"")
(search-forward-regexp "<link rel=\"canonical\" href=\"http://ui.adsabs.harvard.edu/abs/\\(.*\\)/abstract\"/>")
(match-string 1)))
(defun arxiv-get-bibtex-entry (arxiv-bibliographic-code)
"Get bibtex entry for ARXIV-BIBLIOGRAPHIC-CODE."
(with-current-buffer
(url-retrieve-synchronously
(format
"http://adsabs.harvard.edu/cgi-bin/nph-bib_query?bibcode=%s&data_type=BIBTEX&db_key=PRE&nocookieset=1"
arxiv-bibliographic-code))
(goto-char url-http-end-of-headers)
(if (search-forward "Retrieved 1 abstracts" (point-max) t)
(progn
(forward-line)
(buffer-substring (point) (point-max)))
(error "Did not get one entry: %s" (buffer-substring (point) (point-max))))))
(url-retrieve-synchronously (format "https://ui.adsabs.harvard.edu/abs/%s/exportcitation" arxiv-bibliographic-code))
(when (re-search-forward
"<textarea.*>\\(.*\\(?:\n.*\\)*?\\(?:\n\\s-*\n\\|\\'\\)\\)</textarea>"
nil t)
(xml-substitute-special (match-string 1)))))
;;* Getting a bibtex entry for an arXiv article using arXiv API:
;; Retrieves the meta data of an article view arXiv's http API,
@@ -109,9 +104,12 @@
abstract = {%s},
url = {%s},
}"
"Template for BibTeX entries of arXiv articles.")
"Template for BibTeX entries of arXiv articles.")
(declare-function doi-utils-doi-to-bibtex-string "doi-utils")
(declare-function org-ref-replace-nonascii "org-ref-bibtex")
(defun arxiv-get-bibtex-entry-via-arxiv-api (arxiv-number)
"Retrieve meta data for ARXIV-NUMBER.
Returns a formatted BibTeX entry."
@@ -137,8 +135,12 @@ Returns a formatted BibTeX entry."
(bibtex-mode)
(bibtex-set-dialect (parsebib-find-bibtex-dialect) t)
(org-ref-replace-nonascii)
(bibtex-generate-autokey))))
(format arxiv-entry-format-string key title names year arxiv-number category abstract url))))
(bibtex-generate-autokey)))
(doi (assq 'doi entry)))
(if doi
(doi-utils-doi-to-bibtex-string (nth 2 doi))
;; no doi, so we fall back to the simple template
(format arxiv-entry-format-string key title names year arxiv-number category abstract url)))))
(defun arxiv-bibtexify-authors (authors)
@@ -153,33 +155,39 @@ Returns a formatted BibTeX entry."
(let* ((the-current-kill (ignore-errors (current-kill 0 t))) ;; nil if empty kill ring
(arxiv-url-prefix-regexp "^https?://arxiv\\.org/\\(pdf\\|abs\\|format\\)/")
(arxiv-cite-prefix-regexp "^\\(arXiv\\|arxiv\\):")
(arxiv-id-old-regexp "[a-z-]+\\(\\.[A-Z]\\{2\\}\\)?/[0-9]\\{5,7\\}$") ; Ex: math.GT/0309136
(arxiv-id-new-regexp "[0-9]\\{4\\}[.][0-9]\\{4,5\\}\\(v[0-9]+\\)?$") ; Ex: 1304.4404v2
(arxiv-id-old-regexp "[a-z-]+\\(\\.[A-Z]\\{2\\}\\)?/[0-9]\\{5,7\\}") ; Ex: math.GT/0309136
(arxiv-id-new-regexp "[0-9]\\{4\\}[.][0-9]\\{4,5\\}\\(v[0-9]+\\)?") ; Ex: 1304.4404v2
(arxiv-id-regexp (concat "\\(" arxiv-id-old-regexp "\\|" arxiv-id-new-regexp "\\)")))
(cond
(;; make sure current-kill has something in it
;; if current-kill is not a string, return nil
(not (stringp the-current-kill))
nil)
(;; check if current-kill looks like an arxiv ID
;; if so, return it
;; Ex: 1304.4404v2
(s-match (concat "^" arxiv-id-regexp) the-current-kill)
the-current-kill)
(;; check if current-kill looks like an arxiv cite
;; if so, remove the prefix and return
;; Ex: arXiv:1304.4404v2 --> 1304.4404v2
(s-match (concat arxiv-cite-prefix-regexp arxiv-id-regexp) the-current-kill)
(replace-regexp-in-string arxiv-cite-prefix-regexp "" the-current-kill))
(;; check if current-kill looks like an arxiv url
;; if so, remove the url prefix and return
;; Ex: https://arxiv.org/pdf/1304.4404 --> 1304.4404
(s-match (concat arxiv-url-prefix-regexp arxiv-id-regexp) the-current-kill)
(replace-regexp-in-string arxiv-url-prefix-regexp "" the-current-kill))
;; otherwise, return nil
(t
nil))))
(cond
(;; make sure current-kill has something in it
;; if current-kill is not a string, return nil
(not (stringp the-current-kill))
nil)
(;; check if current-kill looks like an arxiv ID
;; if so, return it
;; Ex: 1304.4404v2
(s-match (concat "^" arxiv-id-regexp) the-current-kill)
the-current-kill)
(;; check if current-kill looks like an arxiv cite
;; if so, remove the prefix and return
;; Ex: arXiv:1304.4404v2 --> 1304.4404v2
(s-match (concat arxiv-cite-prefix-regexp arxiv-id-regexp "$") the-current-kill)
(replace-regexp-in-string arxiv-cite-prefix-regexp "" the-current-kill))
(;; check if current-kill looks like an arxiv url
;; if so, remove the url prefix and return
;; Ex: https://arxiv.org/abs/1304.4404 --> 1304.4404
(s-match (concat arxiv-url-prefix-regexp arxiv-id-regexp "$") the-current-kill)
(replace-regexp-in-string arxiv-url-prefix-regexp "" the-current-kill))
(;; check if current-kill looks like an arxiv PDF url
;; if so, remove the url prefix, the .pdf suffix, and return
;; Ex: https://arxiv.org/pdf/1304.4404.pdf --> 1304.4404
(s-match (concat arxiv-url-prefix-regexp arxiv-id-regexp "\\.pdf$") the-current-kill)
(replace-regexp-in-string arxiv-url-prefix-regexp "" (substring the-current-kill 0 (- (length the-current-kill) 4))))
;; otherwise, return nil
(t
nil))))
(defvar bibtex-completion-bibliography)
;;;###autoload
(defun arxiv-add-bibtex-entry (arxiv-number bibfile)
@@ -192,7 +200,7 @@ Returns a formatted BibTeX entry."
(completing-read
"Bibfile: "
(append (f-entries "." (lambda (f) (f-ext? f "bib")))
org-ref-default-bibliography))))
bibtex-completion-bibliography))))
(save-window-excursion
(find-file bibfile)
(goto-char (point-max))
@@ -224,11 +232,12 @@ Returns a formatted BibTeX entry."
(match-string 1))))
(url-copy-file pdf-url pdf)
;; now check if we got a pdf
(if (org-ref-pdf-p pdf)
(org-open-file pdf)
(unless (org-ref-pdf-p pdf)
(delete-file pdf)
(message "Error downloading arxiv pdf %s" pdf-url))))
(defvar bibtex-completion-library-path)
;;;###autoload
(defun arxiv-get-pdf-add-bibtex-entry (arxiv-number bibfile pdfdir)
"Add bibtex entry for ARXIV-NUMBER to BIBFILE.
@@ -243,10 +252,14 @@ key."
(completing-read
"Bibfile: "
(append (f-entries "." (lambda (f) (f-ext? f "bib")))
org-ref-default-bibliography))
(read-directory-name
"PDF directory: "
org-ref-pdf-directory)))
bibtex-completion-bibliography))
(cond
((stringp bibtex-completion-library-path)
bibtex-completion-library-path)
((= 1 (length bibtex-completion-library-path))
(car bibtex-completion-library-path))
(t
(completing-read "PDF dir: " bibtex-completion-library-path)))))
(arxiv-add-bibtex-entry arxiv-number bibfile)
@@ -276,7 +289,13 @@ key."
(setq key (bibtex-read-key "Duplicate Key found, edit: " key))))
(setq key (bibtex-read-key "Key not found, insert: ")))
(insert key)
(arxiv-get-pdf arxiv-number (concat pdfdir key ".pdf")))))
(arxiv-get-pdf arxiv-number (concat pdfdir key ".pdf"))
;; Check that it worked, and insert a field for it.
(when (file-exists-p (concat pdfdir key ".pdf"))
(bibtex-end-of-entry)
(backward-char)
(insert (format " file = {%s}\n " (concat pdfdir key ".pdf")))))))
(provide 'org-ref-arxiv)
;;; org-ref-arxiv.el ends here

View File

@@ -0,0 +1,312 @@
;;; org-ref-bibliography-links.el --- Bibliography and bibliographystyle links
;;
;; Copyright (C) 2021 John Kitchin
;; Author: John Kitchin <jkitchin@andrew.cmu.edu>
;; Keywords: convenience
;; 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 <http://www.gnu.org/licenses/>.
;;
;;; Commentary:
;;
;;; Code:
(defcustom org-ref-latex-bib-resolve-func #'file-relative-name
"Function to expand paths to the bibliography file on latex export.
Use this to convert a path to what you want, e.g. relative to
some directory, absolute, etc."
:type 'function
:group 'org-ref)
(defcustom org-ref-validate-bibliography nil
"If non-nil, validate bibliography files in fontification.
This can be slow, so we don't do it by default."
:type 'boolean
:group 'org-ref)
;;* bibliography* links
(defun org-ref-get-bibfile-path (bibfile)
"Get a path to BIBFILE as local file, or using kpsewhich.
This should allow you to use a bib file that is setup with TeX
variables like BIBINPUTS."
(or (when (file-exists-p bibfile) bibfile)
(let ((f (replace-regexp-in-string
"\n$" ""
(shell-command-to-string (format "kpsewhich %s" bibfile)))))
(unless (string= "" f)
f))))
(defun org-ref-bibliography*-export (cmd bibfiles _desc backend)
"Exporting function for bibliography links.
To be used as a partial function e.g.
(apply-partially \"bibliography\" 'org-ref-bibliography*-export)
Argument CMD is the command it should export to.
Argument BIBFILES is a comma-separated list of strings.
Argument BACKEND is the export backend."
(cond
((eq backend 'latex)
(format "%s{%s}"
cmd
(if (not (string= "" bibfiles))
(replace-regexp-in-string
"\\.bib" ""
(mapconcat
'identity
(mapcar
(lambda (f)
(funcall org-ref-latex-bib-resolve-func (org-ref-get-bibfile-path f)))
(split-string bibfiles ","))
","))
"")))))
(defun org-ref-bibliography-activate (start end path _bracketp)
"Activate a bibliography link.
Adds a warning face to non-existent or invalid bib-files.
START and END are the bounds of the link.
PATH is a comma-separated list of bibfiles."
(goto-char start)
(cl-loop for p in (split-string path ",") do
(setq p (string-trim p))
(search-forward p)
(setq p (org-ref-get-bibfile-path p))
(put-text-property (match-beginning 0) (match-end 0) 'org-ref-bibfile p)
(put-text-property (match-beginning 0) (match-end 0) 'help-echo (format "File exists at %s" p))
;; activate files that don't exist
(when (or (null p) (not (file-exists-p p)))
(put-text-property (match-beginning 0) (match-end 0)
'face 'font-lock-warning-face)
(put-text-property (match-beginning 0) (match-end 0)
'help-echo "This file was not found."))
(when (and p (file-exists-p p))
(when org-ref-validate-bibliography
;; Let's do a validation, but only if it has changed since the last time we checked.
(let* ((mod-time-last-check (or (get-text-property (match-beginning 0)
'mod-time-last-check)
'(0 0 0 0)))
(last-modified (file-attribute-modification-time (file-attributes p)))
(bibtex-valid))
(if (time-equal-p mod-time-last-check last-modified)
(setq bibtex-valid (get-text-property (match-beginning 0) 'bibtex-valid))
;; the times were not equal, so we check and store the state.
(setq bibtex-valid (save-match-data
(with-current-buffer (find-file-noselect p)
(bibtex-validate))))
(put-text-property (match-beginning 0)
(match-end 0)
'mod-time-last-check
last-modified)
(put-text-property (match-beginning 0)
(match-end 0)
'bibtex-valid
bibtex-valid))
(unless bibtex-valid
(put-text-property (match-beginning 0) (match-end 0)
'face 'font-lock-warning-face)
(put-text-property (match-beginning 0) (match-end 0)
'help-echo "This file did not pass `bibtex-validate'.")))))))
(defun org-ref-bibliography*-follow (_path)
"Function to follow bibliography links."
(interactive)
(save-excursion
(unless (get-text-property (point) 'org-ref-bibfile)
(re-search-forward ":"))
(find-file (org-ref-get-bibfile-path (get-text-property (point) 'org-ref-bibfile)))))
(defun org-ref-printbibliography-export (options _desc backend)
"Export function for printbibliography links.
Argument OPTIONS are the options used for the command.
Optional argument BACKEND is the export backend."
(cond
((eq backend 'latex)
;; write out the biblatex bibliography command
(format "\\printbibliography%s"
(if (not (string= "" options))
(format "[%s]" options)
"")))))
(defvar org-ref-cite-types)
(declare-function org-element-map "org-element")
(declare-function org-element-property "org-element")
(declare-function org-element-parse-buffer "org-element")
(declare-function bibtex-completion-show-entry "bibtex-completion")
(declare-function org-ref-possible-bibfiles "org-ref-core")
(declare-function org-ref-parse-cite-path "org-ref-citation-links")
(defun org-ref-insert-bibliography-link ()
"Insert a bibliography link for the files used in this buffer."
(interactive)
(let* ((cite-links (org-element-map (org-element-parse-buffer) 'link
(lambda (lnk)
(when (assoc (org-element-property :type lnk) org-ref-cite-types)
lnk))))
(keys (delete-dups (cl-loop for cl in cite-links append
(cl-loop for ref in (plist-get (org-ref-parse-cite-path
(org-element-property :path cl))
:references)
collect (plist-get ref :key)))))
(files (delete-dups (cl-loop for key in keys collect
(save-window-excursion
(bibtex-completion-show-entry (list key))
(buffer-file-name))))))
(insert (format "bibliography:%s" (string-join files ",")))))
(defun org-ref-bibliography-complete (&optional arg)
"Completion function for bibliography links."
(concat "bibliography:"
(completing-read "Bibliography file: " (org-ref-possible-bibfiles))))
(defun org-ref-nobibliography-complete (&optional arg)
"Completion function for bibliography links."
(concat "nobibliography:"
(completing-read "Bibliography file: " (org-ref-possible-bibfiles))))
(defvar org-ref-default-citation-link)
(defun org-ref-bibtex-store-link ()
"Store a link from a bibtex file. Only supports the cite link.
This essentially the same as the store link in org-bibtex, but it
creates a cite link."
(when (eq major-mode 'bibtex-mode)
(let ((link (concat org-ref-default-citation-link
":&"
(save-excursion
(bibtex-beginning-of-entry)
(cdr (assoc "=key=" (bibtex-parse-entry)))))))
(push (list link) org-stored-links)
(car org-stored-links))))
;; ** bibliography* links
(org-link-set-parameters "bibliography"
:follow #'org-ref-bibliography*-follow
:store #'org-ref-bibtex-store-link
:complete #'org-ref-bibliography-complete
:help-echo "Bibliography link"
:export (apply-partially 'org-ref-bibliography*-export "\\bibliography")
:activate-func #'org-ref-bibliography-activate
:face 'org-link)
(org-link-set-parameters "nobibliography"
:complete #'org-ref-nobibliography-complete
:store #'org-ref-bibtex-store-link
:help-echo "No bibliography link"
:activate-func #'org-ref-bibliography-activate
:follow #'org-ref-bibliography*-follow
:export (apply-partially 'org-ref-bibliography*-export "\\nobibliography")
:face 'org-link)
(org-link-set-parameters "nobibliography*"
:complete #'org-ref-nobibliography-complete
:store #'org-ref-bibtex-store-link
:help-echo "No bibliography link"
:activate-func #'org-ref-bibliography-activate
:follow #'org-ref-bibliography*-follow
:export (apply-partially 'org-ref-bibliography*-export "\\nobibliography*")
:face 'org-link)
(org-link-set-parameters "printbibliography"
:export #'org-ref-printbibliography-export)
;; Note I removed the addbibresource link, it goes in the header, not the document.
;; *** bibliographystyle
(defvar-local org-ref-bst-styles nil
"A list of known bibliography styles. Used to cache results.")
(defun org-ref-clear-bst-cache ()
"Clear `org-ref-bst-styles' to reload it."
(interactive)
(setq org-ref-bst-styles nil))
(defun org-ref-bibliography-styles ()
"Return a list of known bibliography styles.
Returns `org-ref-bst-styles' or sets it and returns it."
(or org-ref-bst-styles
(setq org-ref-bst-styles
(mapcar 'file-name-nondirectory
(mapcar 'file-name-sans-extension
(-flatten
(mapcar (lambda (path)
(setq path (replace-regexp-in-string "!" "" path))
(when (file-directory-p path)
(f-entries path (lambda (f) (f-ext? f "bst")) t)))
(split-string
;; https://tex.stackexchange.com/questions/431948/get-a-list-of-installed-bibliography-styles-with-kpsewhich?noredirect=1#comment1082436_431948
(shell-command-to-string "kpsewhich -expand-path '$BSTINPUTS'")
":"))))))))
(defun org-ref-bibliographystyle-complete-link (&optional arg)
"Completion function for bibliography style links.
ARG is a not used."
(when (executable-find "kpsewhich")
(concat "bibliographystyle:"
(completing-read "Style: " (org-ref-bibliography-styles)))))
(defun org-ref-bibliographystyle-activate (start _end path _bracketp)
"Activation function for bibliography styles.
START is the beginning position of the link.
Optional argument PATH contains the selected style."
(unless (member path (org-ref-bibliography-styles))
(goto-char start)
(search-forward path)
(put-text-property (match-beginning 0) (match-end 0) 'face 'font-lock-warning-face)
(put-text-property (match-beginning 0) (match-end 0) 'help-echo "Unrecognized style")))
(defun org-ref-bibliographystyle-export (style _desc backend)
"Export function for bibliographystyle links.
Argument STYLE is the desired style.
Optional argument BACKEND is the export backend."
(cond
((or (eq backend 'latex)
(eq backend 'beamer))
;; write out the latex bibliography command
(format "\\bibliographystyle{%s}" style))
;; No other backend needs this I think
(t
"")))
(org-link-set-parameters "bibliographystyle"
:complete #'org-ref-bibliographystyle-complete-link
:activate-func #'org-ref-bibliographystyle-activate
:export #'org-ref-bibliographystyle-export)
(provide 'org-ref-bibliography-links)
;;; org-ref-bibliography-links.el ends here

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,919 +0,0 @@
;;; readme.org --- org-ref-citeproc - Citation processor for org-mode
;;; Commentary: This code is style agnostic. It will get information from the
;;; information in `citation-style' and `bibliography-style'. These are defined
;;; in a csl.el file.
;;
;; Conventions:
;; an "entry" is the result of `bibtex-parse-entry'.
;;
;;; Commentary:
;;
(declare-function org-ref-get-bibtex-key-and-file "org-ref-core")
(declare-function org-ref-get-bibtex-keys "org-ref-core")
(declare-function parsebib-find-bibtex-dialect "parsebib")
(defvar org-export-current-backend)
(defvar org-ref-cite-types)
(require 'org-element)
;;; Code:
(defvar *orcp-citation-links* '()
"List of citation links in the text.
A link may have more than one citation in it. These links get
replaced by the new citation text.")
(defvar *orcp-unique-entries* '()
"List of unique (key . entry) parsed bibtex entries in the document.
The list is sorted according to the style. This list eventually
makes up the bibliography.")
(defvar citation-style '()
"Style data for an in-text citation.
For unsrt, a regular cite is superscripted, sorted,
range-collapsed numbers.
LABEL is a function that is run to get the label.
PREFIX goes before a citation.
SUFFIX goes after a citation.
citations are separated by DELIMITER.
SORT specifies that 3, 1, 2 be converted to 1,2,3
COLLAPSE is a function to collapse multiple citations, e.g. 1,2,3 becomes 1-3.
VERTICAL-ALIGN is a function that places the citation, e.g.
superscript, nil for baseline, etc...
Additional entries provide overrides for special citation types.")
(defvar bibliography-style '()
"Bibliography style data.
SORT is a function that sorts the entries, e.g. by author, or
year, or nil. It should take one argument, the list of unique
entries (key . entry).
LABEL is a function that returns how the entry is numbered, or
referenced in the text.
HANGING-INDENT is for the indentation of the entry on the left.
JUSTIFICATION is the overall justification on the right.
SPACING is the number of lines between entries.
HEADER is a string that is inserted above the bibliography.
ENTRIES is a alist of entry type and fields to make the entry from.")
;;* Collect citations
(defun orcp-collect-citations ()
"Return a list of citation links in the document."
(setq *orcp-citation-links*
(cl-loop for link in (org-element-map
(org-element-parse-buffer) 'link 'identity)
if (-contains?
org-ref-cite-types
(org-element-property :type link))
collect link)))
(defun orcp-key-to-entry (key)
"Return a parsed bibtex entry for KEY.
The KEY is found for the bibliography in the file."
(let* ((results (org-ref-get-bibtex-key-and-file key))
(bibfile (cdr results)))
(save-excursion
(with-temp-buffer
(insert-file-contents bibfile)
(bibtex-set-dialect (parsebib-find-bibtex-dialect) t)
(bibtex-search-entry key)
(let ((entry (bibtex-parse-entry t)))
(dolist (cons-cell entry)
(setf (car cons-cell) (downcase (car cons-cell))))
(setf (cdr (assoc "=type=" entry))
(downcase (cdr (assoc "=type=" entry))))
entry)))))
(defun orcp-collect-unique-entries ()
"Return a list of unique entries, sorted as required by the style.
Each entry is (key . entry)."
(let ((keys (org-ref-get-bibtex-keys))
sort-func
entries)
(setq entries
(cl-loop for key in keys
collect (cons key (orcp-key-to-entry key))))
;; Now we should sort them if the style requires it
(setq sort-func (cdr (assoc 'sort bibliography-style)))
(when sort-func
(setq entries (funcall sort-func entries)))
(setq *orcp-unique-entries* entries)))
;;** Unique entry sorting functions
(defun orcp-sort-entries-increasing-year (unique-entries)
"Sort UNIQUE-ENTRIES in increasing year of publication.
i.e. oldest stuff first."
(sort unique-entries
(lambda (a b)
(let* ((e1 (cdr a))
(e2 (cdr b))
(year1 (string-to-number (cdr (assoc "year" e1))))
(year2 (string-to-number (cdr (assoc "year" e2)))))
(> year2 year1)))))
(defun orcp-sort-entries-decreasing-year (unique-entries)
"Sort UNIQUE-ENTRIES in decreasing year.
i.e. most current first."
(reverse (orcp-sort-entries-increasing-year unique-entries)))
(defun orcp-get-entry-field (field entry)
"RETURN FIELD from ENTRY.
Strip extra spaces and carriage returns."
(let ((result (cdr (assoc field entry))))
(when result
(while (string-match "[\n\t\r]\\|[ \t][ \t]+" result)
(setq result (replace-match " " nil t result))))
result))
(defun orcp-sort-entries-alphabetical (unique-entries)
"Sort UNIQUE-ENTRIES alphabetically by first author last name."
(sort unique-entries
(lambda (a b)
(let* ((e1 (cdr a))
(e2 (cdr b))
(authors1 (s-split
" and "
(orcp-get-entry-field "author" e1)))
(author1 (orcp-parse-authorname (car authors1)))
;; lastname is "von last"
(last1 (concat (nth 1 author1) " " (nth 2 author1)))
(authors2 (s-split
" and "
(orcp-get-entry-field "author" e2)))
(author2 (orcp-parse-authorname (car authors2)))
(last2 (concat (nth 1 author2) " " (nth 2 author2))))
(string-lessp last1 last2)))))
;;* Citation labels for one citation key
;; No styling is done here.
(defun orcp-citation-number-label (key unique-entries)
"Find the numeric index of KEY in UNIQUE-ENTRIES and return as a string.
Indexing starts at 0 so we add one."
(number-to-string
(+ 1
(-find-index
(lambda (entry)
(string= key (car entry)))
unique-entries))))
(defun orcp-footnote-label (key unique-entries)
"Return an org footnote label for KEY in UNIQUE-ENTRIES."
(format "[fn:%s]" (orcp-citation-number-label key unique-entries)))
(defun orcp-citation-author-label (key unique-entries)
"Return an author last name label for KEY.
KEY is found in UNIQUE-ENTRIES."
(let* ((i (-find-index
(lambda (entry)
(string= key (car entry)))
unique-entries))
(entry (cdr (nth i unique-entries)))
(authors (s-split
" and "
(orcp-get-entry-field "author" entry)))
(first-author (orcp-parse-authorname (car authors))))
(format "%s" (concat (nth 1 first-author)
(nth 2 first-author)))))
(defun orcp-citation-year-label (key unique-entries)
"Return a year label for KEY.
KEY is found in UNIQUE-ENTRIES."
(let* ((i (-find-index
(lambda (entry)
(string= key (car entry)))
unique-entries))
(entry (cdr (nth i unique-entries)))
(year (orcp-get-entry-field "year" entry)))
(format "%s" year)))
(defun orcp-citation-author-year-label (key unique-entries)
"Return an author last name year label for KEY.
KEY is found in UNIQUE-ENTRIES.
We do not have a disambiguation strategy yet."
(let* ((i (-find-index
(lambda (entry)
(string= key (car entry)))
unique-entries))
(entry (cdr (nth i unique-entries)))
(authors (s-split
" and "
(orcp-get-entry-field "author" entry)))
(first-author (orcp-parse-authorname (car authors)))
(year (orcp-get-entry-field "year" entry)))
(format "%s %s" (concat (nth 1 first-author)
(nth 2 first-author))
year)))
;;* Replacements for citation links
;; Here we have to map over the keys in a citation, sort them according to the
;; style, get replacement labels, concat them together with the style delimiter,
;; add the prefix and suffix, and finally format for the type and output
;; backend.
(defun orcp-get-citation-style (symbol type)
"Get the style info for SYMBOL for a citation TYPE from `citation-style'.
Styles have a default, but allow TYPE overrides. This function
returns the style with the override."
(let (style)
;; first get default style
(setq style (cdr (assoc symbol citation-style)))
;; now check for an override
;; we need to find the type, and the symbol in the type
(when (and (assoc type citation-style)
(assoc symbol (assoc type citation-style)))
(setq style (cdr (assoc symbol (assoc type citation-style)))))
style))
(defun orcp-get-text-replacement (citation-link)
"Return replacement string for CITATION-LINK."
(let* ((type (intern (org-element-property :type citation-link)))
(path (org-element-property :path citation-link))
(keys (s-split "," path))
(entries (mapcar 'orcp-key-to-entry keys))
(label-func (orcp-get-citation-style 'label type))
(delimiter (orcp-get-citation-style 'delimiter type))
(sort-func (orcp-get-citation-style 'sort type))
labels
replacement-text)
;; sort is not coded yet. I am not sure the best data to sort here. the keys?
(when sort-func
(setq keys (sort keys sort-func)))
;; get labels. This function is where you would, for example, create
;; hyperlinks to the bibliography. This function should return a list of
;; strings
(setq labels
(mapcar
(lambda (key)
(funcall label-func key *orcp-unique-entries*))
keys))
;; collapse range - not used yet.
;; now get a string collecting everything
(setq labels (mapconcat 'identity labels delimiter))
(setq replacement-text (concat
(orcp-get-citation-style 'prefix type)
labels
(orcp-get-citation-style 'suffix type)))
;; finally, call formatter
(funcall (or (orcp-get-citation-style 'vertical-align type)
'baseline)
replacement-text)))
(defun orcp-get-citation-replacements ()
"Get a list of replacements for all links in `*orcp-citation-links*'."
(mapcar 'orcp-get-text-replacement *orcp-citation-links*))
;;* Formatted bibliography
(defun orcp-formatted-bibliography ()
"Return the formatted bibliography."
(let* ((spacing (or (cdr (assoc 'spacing bibliography-style)) 1))
(label-func (cdr (assoc 'label bibliography-style)))
(label-prefix (cdr (assoc 'label-prefix bibliography-style)))
(label-suffix (cdr (assoc 'label-suffix bibliography-style)))
(justification (cdr (assoc 'justification bibliography-style)))
(hanging-indent (cdr (assoc 'hanging-indent bibliography-style)))
(header (cdr (assoc 'header bibliography-style)))
(unique-entries (orcp-collect-unique-entries))
(adaptive-fill-function '(lambda () " "))
(indent-tabs-mode nil)
bibliography-string)
(setq bibliography-string
(mapconcat
'identity
;; loop over the entries in the bibliography
(cl-loop for entry in unique-entries
collect
(progn
(let* ((entry-type (downcase
(cdr (assoc "=type=" (cdr entry)))))
(key (cdr (assoc "=key=" (cdr entry))))
(entry-styles (cdr (assoc 'entries bibliography-style)))
(entry-fields
(progn
(if (cdr (assoc (intern entry-type) entry-styles))
(cdr (assoc (intern entry-type) entry-styles))
(warn "%s not found. Using default." entry-type)
(cdr (assoc 't entry-styles))
)))
(funcs (mapcar
(lambda (field)
(if (fboundp (intern
(format "orcp-%s" field)))
(intern
(format "orcp-%s" field))
;; No formatter found. just get the data
`(lambda (entry)
(orcp-get-entry-field
,(symbol-name field) entry))))
entry-fields))
(label (concat label-prefix
(funcall label-func key unique-entries)
label-suffix)))
;; this is the entry. We do this in a buffer to make it
;; easy to indent, fill, etc...
(with-temp-buffer
(insert label)
(insert (mapconcat (lambda (field-func)
(funcall field-func entry))
funcs
""))
(goto-char (point-min))
(forward-word)
;; It doesn't make sense to do this for all formats, e.g.HTML.
;; commenting out for now.
;; (increase-left-margin
;; (point-min) (point-max) hanging-indent)
;; (fill-region (point-min) (point-max) justification)
(buffer-string)))))
;; Here we put in the separator between entries
(cond
;; placeholder for other formats
((eq org-export-current-backend 'html)
" @@html:<br>@@\n")
(t
;; put in a \n for each spacing
(mapconcat 'identity
(cl-loop for i to spacing
collect "\n")
"")))))
;; TODO: figure out header. how do we insert it properly formatted?
bibliography-string))
;;* Text formatting functions.
;; These take text, and format them according to a backend. We derive the
;; backend from `org-export-current-backend' because I anticipate using this
;; during export.
(defun baseline (text)
"Return TEXT."
text)
(defun superscript (text)
"Format TEXT as superscripted."
(cond
((eq org-export-current-backend 'html)
(format "@@html:<sup>%s</sup>@@" text))
;; the catch-all case is org-syntax
(t
(format "^{%s}" text))))
(defun italics (text)
"Format TEXT as italics."
(cond
((eq org-export-current-backend 'html)
(format "@@html:<i>%s</i>@@" text))
;; the catch-all case is org-syntax
(t
(format "/%s/" text))))
(defun bold (text)
"Format TEXT in bold."
(cond
((eq org-export-current-backend 'html)
(format "@@html:<b>%s</b>@@" text))
;; the catch-all case is org-syntax
(t
(format "*%s*" text))))
;;* Field formatting functions
;;These should be style agnostic functions. They take an entry and return a
;; formatted field for the entry, using information from the csl file.
(defun firstname (author-cell)
"Return firstname from AUTHOR-CELL."
(car author-cell))
(defun lastname (author-cell)
"Return lastname from AUTHOR-CELL."
(cdr author-cell))
(defun orcp-author (entry)
"Return formatted author string from the ENTRY.
ENTRY is from `bibtex-parse-entry'.
Style information comes from `bibliography'"
(let* ((style (cdr (assoc 'author bibliography-style)))
(delimiter (cdr (assoc 'delimiter style)))
(name1 (nth 0 (cdr (assoc 'name-order style))))
(name2 (nth 1 (cdr (assoc 'name-order style))))
(name-separator (cdr (assoc 'name-separator style)))
(suffix (cdr (assoc 'suffix style)))
(field-separator (cdr (assoc 'field-separator style)))
(et-al (cdr (assoc 'et-al style)))
(authors (s-split
" and "
(or
(orcp-get-entry-field "author" entry)
"")))
;; parse to list of (first von last jr)
(author-data (mapcar
(lambda (x)
(let ((aud (orcp-parse-authorname x)))
(cons (nth 0 aud)
(concat
(or (nth 1 aud) "")
(or (nth 2 aud) "")
(or (nth 3 aud) "")))))
authors))
;; map first and last names, in order specified in style with separator
(author-names
(mapcar
(lambda (x)
(concat
(funcall name1 x)
name-separator
(funcall name2 x)))
author-data)))
;; check on et-al - not implemented yet
;; work on initialize - not implemented yet
;; mapconcat on delimiter then last author.
(if (= 1 (length author-names))
(concat (car author-names) suffix field-separator)
(concat
(mapconcat
'identity
(butlast author-names)
delimiter)
(cdr (assoc 'last-author-delimiter style))
(car (last author-names))
suffix
field-separator))))
(defun orcp-title (entry)
"Return formatted title for the bibtex ENTRY."
(let* ((style (cdr (assoc 'title bibliography-style)))
(font-style (cdr (assoc 'font-style style)))
(suffix (cdr (assoc 'suffix style)))
(field-separator (cdr (assoc 'field-separator style)))
(title (orcp-get-entry-field "title" entry)))
(concat
(if font-style
(funcall font-style title)
title)
suffix
field-separator)))
(defun orcp-journal (entry)
"Return formatted journal for the bibtex ENTRY."
(let* ((style (cdr (assoc 'journal bibliography-style)))
(font-style (cdr (assoc 'font-style style)))
(suffix (cdr (assoc 'suffix style)))
(field-separator (cdr (assoc 'field-separator style)))
(journal (orcp-get-entry-field "journal" entry)))
(concat
(if font-style
(funcall font-style journal)
journal)
suffix
field-separator)))
(defun orcp-volume (entry)
"Return formatted volume for the bibtex ENTRY."
(let* ((style (cdr (assoc 'volume bibliography-style)))
(font-style (cdr (assoc 'font-style style)))
(prefix (cdr (assoc 'prefix style)))
(suffix (eval (cdr (assoc 'suffix style))))
(field-separator (cdr (assoc 'field-separator style)))
(volume (orcp-get-entry-field "volume" entry)))
(setq volume (concat prefix volume suffix))
(concat
(if font-style
(funcall font-style volume)
volume)
field-separator)))
(defun orcp-issue (entry)
"Return formatted issue for the bibtex ENTRY."
(let* ((style (cdr (assoc 'issue bibliography-style)))
(font-style (cdr (assoc 'font-style style)))
(prefix (cdr (assoc 'prefix style)))
(suffix (cdr (assoc 'suffix style)))
(field-separator (cdr (assoc 'field-separator style)))
(issue (orcp-get-entry-field "number" entry)))
;; issue is optional and isn't always present.
(if (not issue)
field-separator
(setq issue (concat prefix issue suffix))
(if font-style
(funcall font-style
issue)
issue))))
(defun orcp-pages (entry)
"Return formatted pages for the bibtex ENTRY."
(let* ((style (cdr (assoc 'pages bibliography-style)))
(font-style (cdr (assoc 'font-style style)))
(prefix (cdr (assoc 'prefix style)))
(suffix (cdr (assoc 'suffix style)))
(field-separator (cdr (assoc 'field-separator style)))
(pages (orcp-get-entry-field "pages" entry)))
(setq pages (concat prefix pages suffix))
;; collapse-range not supported yet
(concat (if font-style
(funcall font-style
pages)
pages)
field-separator)))
(defun orcp-year (entry)
"Return formatted year for the bibtex ENTRY."
(let* ((style (cdr (assoc 'year bibliography-style)))
(font-style (cdr (assoc 'font-style style)))
(prefix (cdr (assoc 'prefix style)))
(suffix (cdr (assoc 'suffix style)))
(field-separator (cdr (assoc 'field-separator style)))
(year (orcp-get-entry-field "year" entry)))
(setq year (concat prefix year suffix))
;; collapse-range not supported yet
(concat
(if font-style
(funcall font-style
year)
year)
field-separator)))
(defun orcp-doi-formatter (doi)
"Return formatted DOI for different backends."
(cond
((eq org-export-current-backend 'html)
(format "http://dx.doi.org/%s" doi))
(t
(format "doi:%s" doi))))
(defun orcp-doi (entry)
"Return formatted doi for the bibtex ENTRY."
(let* ((style (cdr (assoc 'doi bibliography-style)))
(font-style (cdr (assoc 'font-style style)))
(prefix (cdr (assoc 'prefix style)))
(suffix (cdr (assoc 'suffix style)))
(formatter (cdr (assoc 'formatter style)))
(doi (orcp-get-entry-field "doi" entry)))
(when formatter
(setq doi (funcall formatter doi)))
(setq doi (concat prefix doi suffix))
(if font-style
(funcall font-style
(concat prefix doi suffix))
doi)))
(defun orcp-url (entry)
"Return formatted url for the bibtex ENTRY."
(let* ((style (cdr (assoc 'doi bibliography-style)))
(font-style (cdr (assoc 'font-style style)))
(prefix (cdr (assoc 'prefix style)))
(suffix (cdr (assoc 'suffix style)))
(formatter (cdr (assoc 'formatter style)))
(url (orcp-get-entry-field "url" entry)))
(when formatter
(setq url (funcall formatter url)))
(setq url (concat prefix url suffix))
(if font-style
(funcall font-style
(concat prefix url suffix))
url)))
;;* Data structures for Author names
(defun orcp-unprotect-brackets (piece protected-strings)
"Unprotect PIECE with the information in PROTECTED-STRINGS.
PROTECTED-STRINGS is a list of cons-cells (\"protection\" .
original text)."
(when piece
(mapc
(lambda (cons-cell)
(when (string-match (car cons-cell) piece)
(setq piece (replace-match (cdr cons-cell) t t piece))))
protected-strings))
piece)
;; See http://maverick.inria.fr/~Xavier.Decoret/resources/xdkbibtex/bibtex_summary.html#names for the parsing rules.
(defun orcp-parse-authorname (name)
"Convert an author NAME to (first von last jr) data structure.
Valid name forms are:
First1 First2 Last
First1 First 2 {Last1 Last2}
First1 First2 von1 von2 Last1 Last2
von1 von2 Last1 Last2, Jr., First1 First2
Last1, First1 First2
{Von Last1}, First1 First2
We try to protect strings in curly brackets."
(let* (protected-strings
uuid
ncommas
fields
first von last jr)
;; protect bracketed strings
(while (string-match "{\\(.*\\)}" name)
;; We want our substitute to look like a name, not a von part so we add a
;; capital letter to the front.
(setq uuid (concat "A" (md5 (format "%s%s%s%s%s%s%s"
(random)
(current-time)
(user-uid)
(emacs-pid)
(user-full-name)
user-mail-address
(recent-keys)))))
(add-to-list 'protected-strings (cons uuid (match-string 0 name)))
(setq name (replace-match uuid nil nil name)))
(setq ncommas (s-count-matches "," name))
(cond
;; "First von Last"
((= 0 ncommas)
(setq fields (s-split " " name))
(while (and (s-capitalized? (car fields)) (> (length fields) 1))
(setq first (append first (list (pop fields)))))
(when first
(setq first (mapconcat 'identity first " ")))
;; Next, we get the von part. this is the longest white space delimited
;; string that ends with a lowercase word, and is not the rest of the
;; string.
(let ((last-lower-index nil))
(cl-loop for i to (length fields)
for word in (butlast fields)
if (s-lowercase? word)
do (setq last-lower-index i))
(when last-lower-index
(setq von (mapconcat
'identity
(-slice fields 0 (+ 1 last-lower-index)) " "))
(setq fields (-slice fields (+ 1 last-lower-index)))))
;; all that should be left is the last name but it might be more than one
;; word, e.g. with a Jr. or a two work last name.
(setq last (mapconcat 'identity fields " "))
(mapcar
(lambda (x)
(orcp-unprotect-brackets x protected-strings))
(list first von last jr)))
;; "von Last, First"
((= 1 ncommas)
(setq fields (s-split "," name))
(setq first (nth 1 fields))
;; split first field which could be von Lastname.
(setq fields (s-split " " (car fields)))
(let ((last-lower-index nil))
(cl-loop for i to (length fields)
for word in fields
if (s-lowercase? word)
do (setq last-lower-index i))
(when last-lower-index
(setq von (mapconcat
'identity
(-slice fields 0 (+ 1 last-lower-index)) " "))
(setq fields (-slice fields (+ 1 last-lower-index)))))
;; all that should be left is the last name
(setq last (mapconcat 'identity fields " "))
(mapcar
(lambda (x)
(orcp-unprotect-brackets x protected-strings))
(list first von last jr)))
;; "von Last, Jr, First"
((= 2 ncommas)
(setq fields (s-split "," name))
(setq first (nth 2 fields))
(setq jr (nth 1 fields))
;; split first field which could be von Lastname.
(setq fields (s-split " " (car fields)))
(let ((last-lower-index nil))
(cl-loop for i to (length fields)
for word in fields
if (s-lowercase? word)
do (setq last-lower-index i))
(when last-lower-index
(setq von (mapconcat 'identity (-slice fields 0 (+ 1 last-lower-index)) " "))
(setq fields (-slice fields (+ 1 last-lower-index)))))
;; all that should be left is the last name
(setq last (mapconcat 'identity fields " "))
(mapcar
(lambda (x)
(orcp-unprotect-brackets x protected-strings))
(list first von last jr))))))
;;* Collapse numeric range
(defun orcp-collapse-numeric-range (cites delimiter)
"TODO use style info.
Collapse a numeric list of CITES into a range.
Collapsed ranges are separated by DELIMITER."
(let (n
(groups '()))
(while cites
(setq n (pop cites))
(if (and (caar groups) (= (- n 1) (elt (car groups) 0)))
(setf (car groups) (append `(,n) (car groups)))
(setf groups (append `((,n)) groups))))
;; Now for each group
(mapconcat 'identity
(mapcar
(lambda (lst)
(cond
((>= (length lst) 3)
(format "%s-%s" (car lst) (car (last lst))))
((= (length lst) 2)
(format "%s,%s" (nth 0 lst) (nth 1 lst)))
(t
(number-to-string (car lst)))))
(mapcar 'reverse (reverse groups)))
delimiter)))
;;* Putting it all together
(defun sentence-beginning-p ()
"Determine if point is at the beginning of a sentence.
The idea is to move forward a sentence, then back. If the point
doesn't move, it means you were at the beginning of a sentence."
(let ((cp (point)))
(save-excursion
(forward-sentence)
(backward-sentence)
(= cp (point)))))
(defun orcp-citeproc (&optional backend)
"Format citations and bibliography for BACKEND.
Warning. Destructive to your document! Will replace links.
Meant to be used in export on a temporary version of the
documents."
;; Get the style from bibliographystyle link
;; and eliminate bibliography style links
;; This will load all style modules
(cl-loop for link in (org-element-map
(org-element-parse-buffer) 'link 'identity)
if (string= "bibliographystyle"
(org-element-property :type link))
do
;; get path for style and load it
(load-library (org-element-property :path link))
;; get rid of the link in the buffer
(setf (buffer-substring (org-element-property :begin link)
(org-element-property :end link))
""))
(orcp-collect-citations)
(orcp-collect-unique-entries)
(let ((link-replacements (cl-loop for link in *orcp-citation-links*
for repl in (orcp-get-citation-replacements)
collect
(list repl
(org-element-property :begin link)
(org-element-property :end link))))
(bibliography-string (orcp-formatted-bibliography))
punctuation
trailing-space
bibliography-link)
;; replace citation links
(cl-loop for (repl start end) in (reverse link-replacements)
for link in (reverse *orcp-citation-links*)
do
;; chomp leading spaces if needed
(when (orcp-get-citation-style
'chomp-leading-space
(intern (org-element-property :type link)))
(goto-char start)
(while (and (not (sentence-beginning-p))
(looking-back " " (- (point) 2)))
(delete-char -1)
(setq start (- start 1))
(setq end (- end 1))))
;; chomp trailing spaces if needed
(when (orcp-get-citation-style
'chomp-trailing-space
(intern (org-element-property :type link)))
(goto-char end)
(while (looking-back " " (- (point) 2))
(delete-char 1)))
;; Check for transposing punctuation
(setq punctuation nil)
(when (orcp-get-citation-style
'transpose-punctuation
(intern (org-element-property :type link)))
;; goto end of link
(goto-char end)
(when (looking-at "\\.\\|,\\|;")
(setq punctuation (buffer-substring end (+ 1 end)))
(delete-char 1)))
;; preserve trailing space
(goto-char end)
(setq trailing-space (if (looking-back " " (line-beginning-position)) " " ""))
(setf (buffer-substring start end) (concat repl trailing-space))
(when punctuation
(goto-char start)
;; I can't figure out why this is necessary. I would have thought
;; the chomp leading spaces would get it.
(when (thing-at-point 'whitespace)
(delete-char -1))
(insert punctuation)))
;; Insert bibliography section at the bibliography link
(setq bibliography-link (cl-loop for link
in (org-element-map
(org-element-parse-buffer)
'link 'identity)
if (string= "bibliography"
(org-element-property :type link))
collect link))
(pcase (length bibliography-link)
((pred (< 1)) (error "Only one bibliography link allowed"))
((pred (= 1))
;; replace bibliography link
(setq bibliography-link (car bibliography-link))
(setf (buffer-substring (org-element-property :begin bibliography-link)
(org-element-property :end bibliography-link))
bibliography-string))
((pred (= 0))
;; no bibliography link in document
(when link-replacements
(message "Warning: No bibliography link found although there are citations to process"))))))
;; * the end
(provide 'org-ref-citeproc)
;;; org-ref-citeproc.el ends here

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,594 @@
;;; org-ref-export.el --- org-ref-export library -*- lexical-binding: t; -*-
;;
;; Copyright (C) 2021 John Kitchin
;; Author: John Kitchin <jkitchin@andrew.cmu.edu>
;; Keywords: convenience
;; 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 <http://www.gnu.org/licenses/>.
;;
;;; Commentary:
;; This is an export library that uses CSL to process the citations and bibliography.
;;
;; It is intended for non-LaTeX exports, but you can also use it with LaTeX if
;; you want to avoid using bibtex/biblatex for some reason.
;;
;; The default style is set by a CSL-STYLE keyword or
;; `org-ref-csl-default-style'. If this is an absolute or relative path that
;; exists, it is used. Otherwise, it looks in `org-cite-csl-styles-dir' from
;; `org-cite' if it is defined, and in the citeproc/csl-styles directory in
;; `org-ref' otherwise.
;;
;; The default locale is set by a CSL-LOCALE keyword or
;; `org-ref-csl-default-locale'. This is looked for in
;; `org-cite-csl-locales-dir' if it is defined, and otherwise in the csl-locales
;; directory of `org-ref'.
;;
;; Note that citeproc does not do anything for cross-references, so if non-LaTeX
;; export is your goal, you may want to use org-ref-refproc.el to handle
;; cross-references.
;;
;;; Code:
(eval-when-compile
(require 'hydra))
(defvar hfy-user-sheet-assoc) ; to quiet compiler
(require 'ox-org)
(require 'citeproc)
(defcustom org-ref-backend-csl-formats
'((html . html)
(latex . latex)
(md . plain)
(org . org)
(ascii . plain)
(odt . org-odt))
"Mapping of export backend to csl-backends."
:type '(alist :key-type (symbol) :value-type (symbol))
:group 'org-ref)
(defcustom org-ref-cite-internal-links 'auto
"Should be on of
- 'bib-links :: link cites to bibliography entries
- 'no-links :: do not link cites to bibliography entries
- nil or 'auto :: add links based on the style."
:type '(choice bib-links no-links auto nil)
:group 'org-ref)
(defcustom org-ref-csl-default-style "chicago-author-date-16th-edition.csl"
"Default csl style to use.
Should be a csl filename, or an absolute path to a csl filename."
:type 'string
:group 'org-ref)
(defcustom org-ref-csl-default-locale "en-US"
"Default csl locale to use."
:type 'string
:group 'org-ref)
(defcustom org-ref-csl-label-aliases
'((("app" "apps") . "appendix")
(("art" "arts") . "article-locator")
(("bk" "bks") . "book")
(("can") . "canon")
(("ch" "chap" "chaps" "chapt") . "chapter")
(("col" "cols") . "column")
(("el") . "elocation")
(("eq" "eqs") . "equation")
(("fig" "figs") . "figure")
(("fol" "fols") . "folio")
(("iss") . "issue")
(("l" "ll") . "line")
(("n" "nn") . "note")
;; number is not listed in the url in the docstring
(("no" "nos" "#") . "number")
(("op" "opp") . "opus")
(("p" "pp" "pg" "pgs") . "page")
(("para" "paras" "" "¶¶" "§" "§§") . "paragraph")
(("pt" "pts") . "part")
(("sec" "secs") . "section")
(("s.v" "s.vv") . "sub verbo")
(("sup" "supp") . "supplement")
(("tab" "tabs") . "table")
(("ts") . "timestamp")
(("ti" "tit") . "title")
(("v" "vv") . "verse")
(("vol" "vols") . "volume"))
"A-list of aliases for a csl label.
The car is a list of possible aliases (including if they end in a .
This list was adapted from `org-cite-csl--label-alist'.
See https://github.com/citation-style-language/documentation/blob/master/specification.rst#locators"
:type '(alist :key-type (list (repeat string)) :value-type string)
:group 'org-ref)
(defun org-ref-dealias-label (alias)
"Return the full, de-aliased label for ALIAS.
Looked up from `org-ref-csl-label-aliases'.
I added this because I think it is reasonable to expect if you
write pg. 2 that it will show that way when rendered. At the
moment that is not the case, and only page is accepted. This is
actually done in oc-csl too, although it uses a flat a-list."
(or (cdr (assoc "page" org-ref-csl-label-aliases
(lambda (x1 _x2)
(or (member alias x1)
(member (concat (downcase alias) ".") x1)))))
alias))
(defun org-ref-get-cite-links ()
"Return list of cite links in the order they appear in the buffer."
(org-element-map (org-element-parse-buffer) 'link
(lambda (lnk)
(when (assoc (org-element-property :type lnk) org-ref-cite-types)
lnk))))
(defun org-ref-ref-csl-data (ref type)
"Return the CSL alist for a REF of TYPE.
REF is a plist data structure returned from `org-ref-parse-cite-path'."
;; I believe the suffix contains "label locator suffix"
;; where locator is a number, or maybe a range of numbers like 5-6.
;; label is something like page or chapter
;; and the rest is the suffix text.
;; For example: ch. 5, for example
;; would be label = ch., locator=5, ",for example" as suffix.
(let* ((full-suffix (string-trim (or (plist-get ref :suffix) "")))
locator
label locator suffix)
;; org-cite is more sophisticated than this and would allow things like 5, 6
;; and 12. I am not sure about what all should be supported yet. I guess the
;; idea there is you use everything from the first to last number as the
;; locator, but that seems tricky, what about something like: 5, 6 and 12,
;; because he had 3 books. One solution might be some kind of delimiter,
;; e.g. {5, 6 and 12}, because he had 3 books.
(if (and (string-match
(rx
;; optional label
(group-n 1 (optional
(regexp (regexp-opt (cl-loop for (abbrvs . full)
in org-ref-csl-label-aliases
append (append abbrvs (list full)))))))
(optional (one-or-more space))
;; number or numeric ranges
(group-n 2 (one-or-more digit) (optional "-" (one-or-more digit)))
;; everything else
(group-n 3 (* ".")))
full-suffix)
(match-string 2 full-suffix)
(not (string= "" (match-string 2 full-suffix))))
;; We found a locator
(setq label (match-string 1 full-suffix)
locator (match-string 2 full-suffix)
suffix (match-string 3 full-suffix))
(setq label nil
locator nil
suffix full-suffix))
;; Let's assume if you have a locator but not a label that you mean page.
(when (and locator (string= "" (string-trim label)))
(setq label "page"))
`((id . ,(plist-get ref :key))
(prefix . ,(plist-get ref :prefix))
(suffix . ,suffix)
(locator . ,locator)
(label . ,(when label (org-ref-dealias-label (string-trim label))))
;; TODO: proof of concept and not complete. I did not go through all the
;; types to see what else should be in here.
(suppress-author . ,(not (null (member type
'("citenum"
"citeyear"
"citeyear*"
"citedate"
"citedate*"
"citetitle"
"citetitle*"
"citeurl"))))))))
(declare-function org-ref-find-bibliography "org-ref-core")
(defun org-ref-process-buffer (backend &optional subtreep)
"Process the citations and bibliography in the org-buffer.
Usually run on a copy of the buffer during export.
BACKEND is the org export backend."
(save-restriction
(when subtreep
(org-narrow-to-subtree))
(let* ((csl-backend (or (cdr (assoc backend org-ref-backend-csl-formats)) 'plain))
(style (or (cadr (assoc "CSL-STYLE"
(org-collect-keywords
'("CSL-STYLE"))))
org-ref-csl-default-style))
(locale (or (cadr (assoc "CSL-LOCALE"
(org-collect-keywords
'("CSL-LOCALE"))))
org-ref-csl-default-locale))
(proc (citeproc-create
;; The style
(cond
((file-exists-p style)
style)
;; In a user-dir
((and (boundp 'org-cite-csl-styles-dir)
(file-exists-p (f-join org-cite-csl-styles-dir style)))
(f-join org-cite-csl-styles-dir style))
;; provided by org-ref
((file-exists-p (expand-file-name style
(f-join (file-name-directory
(locate-library "org-ref"))
"citeproc/csl-styles")))
(expand-file-name style (f-join
(file-name-directory
(locate-library "org-ref"))
"citeproc/csl-styles")))
(t
(error "%s not found" style)))
;; item-getter
;; (citeproc-itemgetter-from-bibtex (org-ref-find-bibliography))
(citeproc-hash-itemgetter-from-any (org-ref-find-bibliography))
;; locale getter
(citeproc-locale-getter-from-dir (cond
((boundp 'org-cite-csl-locales-dir)
org-cite-csl-locales-dir)
(t
(f-join (file-name-directory
(locate-library "org-ref"))
"citeproc/csl-locales"))))
;; the actual locale
locale))
;; list of links in the buffer
(cite-links (org-element-map (org-element-parse-buffer) 'link
(lambda (lnk)
(when (assoc (org-element-property :type lnk) org-ref-cite-types)
lnk))))
(cites (cl-loop for cl in cite-links collect
(let* ((cite-data (org-ref-parse-cite-path (org-element-property :path cl)))
(common-prefix (or (plist-get cite-data :prefix) ""))
(common-suffix (or (plist-get cite-data :suffix) ""))
(refs (plist-get cite-data :references))
(type (org-element-property :type cl))
(cites (cl-loop for ref in refs collect
(org-ref-ref-csl-data ref type))))
;; TODO: update eventually
;; https://github.com/andras-simonyi/citeproc-el/issues/46
;; To handle common prefixes, suffixes, I just concat
;; them with the first/last entries. That is all that
;; is supported for now. Combine common/local prefix
(setf (cdr (assoc 'prefix (cl-first cites)))
(concat common-prefix
(cdr (assoc 'prefix (cl-first cites)))))
;; Combine local/common suffix
(setf (cdr (assoc 'suffix (car (last cites))))
(concat (cdr (assoc 'suffix (car (last cites))))
common-suffix))
;; https://github.com/andras-simonyi/citeproc-el#creating-citation-structures
(citeproc-citation-create
:cites cites
;; TODO: proof of concept, incomplete if this is
;; true, the citation is not parenthetical
:suppress-affixes (let ((type (org-element-property :type cl)))
(when (member type '("citet"
"citet*"
"citenum"))
t))
;; TODO: this is proof of concept, and not complete.
;; mode is one of suppress-author, textual,
;; author-only, year-only, or nil for default. These
;; are not all clear to me.
:mode (let ((type (org-element-property :type cl)))
(cond
((member type '("citet" "citet*"))
'textual)
((member type '("citeauthor" "citeauthor*"))
'author-only)
((member type '("citeyear" "citeyear*"))
'year-only)
((member type '("citedate" "citedate*"))
'suppress-author)
(t
nil)))
;; I think the capitalized styles are what this is for
:capitalize-first (string-match
"[A-Z]"
(substring
(org-element-property :type cl) 0 1))
;; I don't know where this information would come from.
:note-index nil
:ignore-et-al nil))))
(rendered-citations (progn (citeproc-append-citations cites proc)
(citeproc-render-citations proc csl-backend org-ref-cite-internal-links)))
;; I only use the returned bibliography string. citeproc returns a
;; bunch of other things related to offsets and linespacing, but I
;; don't know what you do with these, so just ignore them here.
(rendered-bib (car (citeproc-render-bib proc csl-backend)))
;; The idea is we will wrap each citation and the bibliography in
;; org-code so it exports appropriately.
(cite-formatters '((html . "@@html:%s@@")
(latex . "@@latex:%s@@")
(odt . "@@odt:%s@@")))
(bib-formatters '((html . "\n#+BEGIN_EXPORT html\n%s\n#+END_EXPORT\n")
(latex . "\n#+BEGIN_EXPORT latex\n%s\n#+END_EXPORT\n")
(odt . "\n#+BEGIN_EXPORT ODT\n%s\n#+END_EXPORT\n"))))
;; replace the cite links
(cl-loop for cl in (reverse cite-links) for rc in (reverse rendered-citations) do
(cl--set-buffer-substring (org-element-property :begin cl)
(org-element-property :end cl)
(format (or
(cdr (assoc backend cite-formatters))
"%s")
(concat
rc
;; Add on extra spaces that were
;; following it.
(make-string
(or
(org-element-property :post-blank cl) 0)
? )))))
;; replace the bibliography
(org-element-map (org-element-parse-buffer) 'link
(lambda (lnk)
(cond
((string= (org-element-property :type lnk) "bibliography")
(cl--set-buffer-substring (org-element-property :begin lnk)
(org-element-property :end lnk)
(format (or
(cdr (assoc backend bib-formatters))
"%s")
rendered-bib)))
;; We just get rid of nobibliography links.
((string= (org-element-property :type lnk) "nobibliography")
(cl--set-buffer-substring (org-element-property :begin lnk)
(org-element-property :end lnk)
"")))))
;; For LaTeX we need to define the citeprocitem commands
;; see https://www.mail-archive.com/emacs-orgmode@gnu.org/msg138546.html
(when (eq backend 'latex)
(goto-char (point-min))
(insert "#+latex_header: \\makeatletter
#+latex_header: \\newcommand{\\citeprocitem}[2]{\\hyper@linkstart{cite}{citeproc_bib_item_#1}#2\\hyper@linkend}
#+latex_header: \\makeatother\n")))))
(defun org-ref-export-to (backend &optional async subtreep visible-only
body-only info)
"Export buffer to BACKEND.
See `org-export-as' for the meaning of ASYNC SUBTREEP
VISIBLE-ONLY BODY-ONLY and INFO."
(let* ((fname (buffer-file-name))
(extensions '((html . ".html")
(latex . ".tex")
(ascii . ".txt")
(odt . ".odf")))
(cp (point))
(mm) ;marker to save place
(export-name (concat (file-name-sans-extension fname)
(or (cdr (assoc backend extensions)) ""))))
(org-export-with-buffer-copy
;; Note I use a marker here to make sure we stay in the same place we were.
;; This is more robust than save-excursion I think, since processing moves
;; points around. In theory the marker should move too.
(setq mm (make-marker))
(move-marker mm cp)
;; make sure we expand includes
(org-export-expand-include-keyword)
(goto-char (marker-position mm))
(org-ref-process-buffer backend subtreep)
(message-box (buffer-substring (line-beginning-position) (line-end-position)))
(set-marker mm nil)
(pcase backend
;; odt is a little bit special, and is missing one argument
('odt (org-open-file (org-odt-export-to-odt async subtreep visible-only
info)
'system))
(_
(org-open-file (org-export-to-file backend export-name
async subtreep visible-only
body-only info)
'system))))))
;; I guess I tried to use apply-partially here, and it did not work, so these
;; are each defined manually
(defun org-ref-export-to-html (&optional async subtreep visible-only
body-only info)
"Export the buffer to HTML and open.
See `org-export-as' for the meaning of ASYNC SUBTREEP
VISIBLE-ONLY BODY-ONLY and INFO."
(org-ref-export-to 'html async subtreep visible-only
body-only info))
(defun org-ref-export-to-ascii (&optional async subtreep visible-only
body-only info)
"Export the buffer to ascii and open.
See `org-export-as' for the meaning of ASYNC SUBTREEP
VISIBLE-ONLY BODY-ONLY and INFO."
(org-ref-export-to 'ascii async subtreep visible-only
body-only info))
(defun org-ref-export-to-pdf (&optional async subtreep visible-only
body-only info)
"Export the buffer to PDF via LaTeX and open.
See `org-export-as' for the meaning of ASYNC SUBTREEP
VISIBLE-ONLY BODY-ONLY and INFO."
(let ((org-export-before-parsing-hook '(org-ref-csl-preprocess-buffer)))
(org-open-file (org-latex-export-to-pdf async subtreep visible-only
body-only info))))
(defun org-ref-export-to-latex (&optional async subtreep visible-only
body-only info)
"Export the buffer to LaTeX and open.
See `org-export-as' for the meaning of ASYNC SUBTREEP
VISIBLE-ONLY BODY-ONLY and INFO."
(org-ref-export-to 'latex async subtreep visible-only
body-only info))
(defun org-ref-export-to-odt (&optional async subtreep visible-only
body-only info)
"Export the buffer to ODT and open.
See `org-export-as' for the meaning of ASYNC SUBTREEP
VISIBLE-ONLY BODY-ONLY and INFO."
(require 'htmlfontify)
(unless (boundp 'hfy-user-sheet-assoc) (setq hfy-user-sheet-assoc nil))
(org-ref-export-to 'odt async subtreep visible-only
body-only info))
(defun org-ref-export-as-org (&optional _async subtreep visible-only
body-only info)
"Export the buffer to an ORG buffer and open.
We only make a buffer here to avoid overwriting the original file.
See `org-export-as' for the meaning of ASYNC SUBTREEP
VISIBLE-ONLY BODY-ONLY and INFO."
(let* ((export-buf "*org-ref ORG Export*")
export)
(org-export-with-buffer-copy
(org-ref-process-buffer 'org subtreep)
(setq export (org-export-as 'org subtreep visible-only body-only info))
(with-current-buffer (get-buffer-create export-buf)
(erase-buffer)
(org-mode)
(insert export)))
(pop-to-buffer export-buf)))
(defun org-ref-export-to-message (&optional _async subtreep visible-only
body-only info)
"Export to ascii and insert in an email message."
(let* ((backend 'ascii)
(content (org-export-with-buffer-copy
(org-ref-process-buffer backend subtreep)
(org-export-as backend subtreep visible-only
body-only info))))
(compose-mail)
(message-goto-body)
(insert content)
(message-goto-to)))
(org-export-define-derived-backend 'org-ref 'org
:menu-entry
'(?r "Org-ref export"
((?a "to Ascii" org-ref-export-to-ascii)
(?h "to html" org-ref-export-to-html)
(?l "to LaTeX" org-ref-export-to-latex)
(?p "to PDF" org-ref-export-to-pdf)
(?o "to ODT" org-ref-export-to-odt)
(?O "to Org buffer" org-ref-export-as-org)
(?e "to email" org-ref-export-to-message))))
;; An alternative to this exporter is to use an `org-export-before-parsing-hook'
;; (add-hook 'org-export-before-parsing-hook 'org-ref-csl-preprocess-buffer)
(defun org-ref-csl-preprocess-buffer (backend)
"Preprocess the buffer in BACKEND export.
Note this may not work as expected, what about subtreep? The hook
function just takes one argument. For now we rely on
`buffer-narrowed-p' and an org-heading at the beginning.
I am not positive on this though."
(org-ref-process-buffer backend (and (buffer-narrowed-p)
(save-excursion
(goto-char (point-min))
(org-at-heading-p)))))
;; A hydra exporter with preprocessors
(defhydradio org-ref ()
(natmove "natmove")
(citeproc "CSL citations")
(refproc "cross-references")
(acrossproc "Acronyms, glossary")
(idxproc "Index")
(bblproc "BBL citations"))
(defun org-ref-export-from-hydra (&optional arg)
"Run the export dispatcher with the desired hooks selected in `org-ref-export/body'."
(interactive "P")
(when (and org-ref/citeproc org-ref/bblproc)
(error "You cannot use CSL and BBL at the same time."))
(let ((org-export-before-parsing-hook org-export-before-parsing-hook))
(when org-ref/citeproc
(cl-pushnew 'org-ref-csl-preprocess-buffer org-export-before-parsing-hook))
(when org-ref/refproc
(cl-pushnew 'org-ref-refproc org-export-before-parsing-hook))
(when org-ref/acrossproc
(cl-pushnew 'org-ref-acrossproc org-export-before-parsing-hook))
(when org-ref/idxproc
(cl-pushnew 'org-ref-idxproc org-export-before-parsing-hook))
(when org-ref/bblproc
(unless (featurep 'org-ref-natbib-bbl-citeproc)
(require 'org-ref-natbib-bbl-citeproc))
(cl-pushnew 'org-ref-bbl-preprocess org-export-before-parsing-hook))
;; this goes last since it moves cites before they might get replaced.
(when org-ref/natmove
(cl-pushnew 'org-ref-cite-natmove org-export-before-parsing-hook))
(org-export-dispatch arg)))
(defhydra org-ref-export (:color red)
"
_C-n_: natmove % -15`org-ref/natmove _C-c_: citeproc % -15`org-ref/citeproc^^^ _C-r_: refproc % -15`org-ref/refproc^^^
_C-a_: acrossproc % -15`org-ref/acrossproc _C-i_: idxproc % -15`org-ref/idxproc^^^ _C-b_: bblproc % -15`org-ref/bblproc^^^
"
("C-n" (org-ref/natmove) nil)
("C-c" (org-ref/citeproc) nil)
("C-r" (org-ref/refproc) nil)
("C-a" (org-ref/acrossproc) nil)
("C-i" (org-ref/idxproc) nil)
("C-b" (org-ref/bblproc) nil)
("e" org-ref-export-from-hydra "Export" :color blue)
("q" nil "quit"))
(provide 'org-ref-export)
;;; org-ref-export.el ends here

File diff suppressed because it is too large Load Diff

View File

@@ -1,750 +0,0 @@
;;; org-ref-helm-bibtex.el --- Customization of helm-bibtex for org-ref -*- lexical-binding: t; -*-
;; Copyright (C) 2016 John Kitchin
;; Author: John Kitchin <jkitchin@andrew.cmu.edu>
;; Keywords:
;; 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 <http://www.gnu.org/licenses/>.
;;; Commentary:
;; This file defines the completion engine for org-ref using `helm-bibtex'.
(declare-function 'org-ref-find-bibliography "org-ref-core.el")
(declare-function 'org-ref-get-bibtex-key-and-file "org-ref-core.el")
(defvar org-ref-get-pdf-filename-function)
(defvar org-ref-default-citation-link)
(defvar org-ref-cite-types)
(defvar org-ref-insert-link-function)
(defvar org-ref-insert-cite-function)
(defvar org-ref-insert-label-function)
(defvar org-ref-insert-ref-function)
(defvar org-ref-cite-onclick-function)
(defvar org-ref-insert-cite-key)
;;; Code:
(require 'helm-config)
(require 'helm)
(require 'helm-bibtex)
(require 'helm-utils)
(require 'org-ref-helm)
(require 'async)
(require 'package)
;;;###autoload
(defun org-ref-bibtex-completion-completion ()
"Use helm and helm-bibtex for completion."
(interactive)
;; Define core functions for org-ref
(setq org-ref-insert-link-function 'org-ref-helm-insert-cite-link
org-ref-insert-cite-function 'org-ref-helm-insert-cite-link
org-ref-insert-label-function 'org-ref-helm-insert-label-link
org-ref-insert-ref-function 'org-ref-helm-insert-ref-link
org-ref-cite-onclick-function 'org-ref-cite-click-helm))
(org-ref-bibtex-completion-completion)
(define-key org-mode-map
(kbd org-ref-insert-cite-key)
org-ref-insert-link-function)
(defcustom org-ref-bibtex-completion-actions
'(("Insert citation" . helm-bibtex-insert-citation)
("Open PDF, URL or DOI" . helm-bibtex-open-any)
("Open URL or DOI in browser" . helm-bibtex-open-url-or-doi)
("Insert reference" . helm-bibtex-insert-reference)
("Insert BibTeX key" . helm-bibtex-insert-key)
("Insert BibTeX entry" . helm-bibtex-insert-bibtex)
("Insert formatted citation(s)" . (lambda (_)
(insert
(mapconcat 'identity
(cl-loop for key in (helm-marked-candidates)
collect (org-ref-format-entry key))
"\n\n"))))
("Attach PDF to email" . helm-bibtex-add-PDF-attachment)
("Edit notes" . helm-bibtex-edit-notes)
("Show entry" . helm-bibtex-show-entry)
("Add keywords to entries" . org-ref-helm-tag-entries)
("Copy entry to clipboard" . bibtex-completion-copy-candidate)
("Add PDF to library" . helm-bibtex-add-pdf-to-library))
"Cons cells of string and function to set the actions of `helm-bibtex' to.
The car of cons cell is the string describing the function.
The cdr of the the cons cell is the function to use."
:type '(alist :key-type (string) :value-type (function))
:group 'org-ref)
(cl-loop for i from 0 to (length org-ref-bibtex-completion-actions)
for ccell in org-ref-bibtex-completion-actions
do
(helm-delete-action-from-source (car ccell) helm-source-bibtex)
(helm-add-action-to-source
(car ccell)
(cdr ccell)
helm-source-bibtex))
(defcustom org-ref-bibtex-completion-format-org
'org-ref-bibtex-completion-format-org
"Function for how `helm-bibtex' inserts citations."
:type 'function
:group 'org-ref)
(setf (cdr (assoc 'org-mode bibtex-completion-format-citation-functions))
org-ref-bibtex-completion-format-org)
(setq org-ref-insert-cite-function 'org-ref-helm-insert-cite-link
org-ref-cite-onclick-function 'org-ref-cite-click-helm)
(defcustom org-ref-bibtex-completion-add-keywords-field t
"Whether to add the `keywords' field to bibtex-completion."
:group 'org-ref
:type 'boolean)
;;* Helm bibtex setup.
(when org-ref-bibtex-completion-add-keywords-field
(unless (or (member 'keywords bibtex-completion-additional-search-fields)
(member "keywords" bibtex-completion-additional-search-fields))
;; Both symbol and string values are accepted, but b-c-a-s-f's
;; Custom :type specifies string.
(push "keywords" bibtex-completion-additional-search-fields))
(let ((display-format
(alist-get t bibtex-completion-display-formats)))
(unless (string-match-p "{keywords:"
display-format)
(setf (alist-get t bibtex-completion-display-formats)
(concat display-format " ${keywords:31}")))))
(defun bibtex-completion-copy-candidate (_candidate)
"Copy the selected bibtex entries to the clipboard.
Used as a new action in `helm-bibtex'.
CANDIDATE is ignored."
(with-temp-buffer
(bibtex-mode)
(mapc #'insert-file-contents
(-flatten (list bibtex-completion-bibliography)))
(let ((entries '()))
(cl-loop for bibtex-key in (helm-marked-candidates)
do
(goto-char (point-min))
(re-search-forward (concat "^@\\(" parsebib--bibtex-identifier
"\\)[[:space:]]*[\(\{][[:space:]]*"
(regexp-quote bibtex-key)
"[[:space:]]*,"))
(cl-pushnew (buffer-substring
(bibtex-beginning-of-entry)
(bibtex-end-of-entry))
entries))
(with-temp-buffer
(dolist (entry entries)
(insert (format "%s\n\n" entry)))
(kill-new (buffer-string))))))
(defun org-ref-helm-tag-entries (_candidates)
"Set tags on selected bibtex entries from `helm-bibtex'.
User is prompted for tags. This function is called from `helm-bibtex'.
Argument CANDIDATES helm candidates."
(message "")
(let* ((keys (helm-marked-candidates))
(entry (bibtex-completion-get-entry (car keys)))
(field (cdr (assoc-string "keywords" entry)))
(value (when field (replace-regexp-in-string "^{\\|}$" "" field)))
(keywords (read-string "Keywords (comma separated): "
(when (and value (not (equal "" value)))
(concat value ", ")))))
(cl-loop for key in keys
do
(save-window-excursion
(bibtex-completion-show-entry (list key))
;; delete keyword field if empty
(if (equal "" keywords)
(save-restriction
(bibtex-narrow-to-entry)
(goto-char (car (cdr (bibtex-search-forward-field "keywords" t))))
(bibtex-kill-field))
(bibtex-set-field
"keywords"
(concat
(if (listp keywords)
(if (string-match value keywords)
(and (replace-match "")
(mapconcat 'identity keywords ", "))
(mapconcat 'identity keywords ", "))
;; remove trailing comma
(replace-regexp-in-string ", $" "" keywords)))))
(save-buffer)))))
(defun org-ref-bibtex-completion-format-org (keys)
"Insert selected KEYS as cite link.
Append KEYS if you are on a link.
Technically, this function should return a string that is
inserted by helm. This function does the insertion and gives helm
an empty string to insert. This lets us handle appending to a
link properly.
In the `helm-bibtex' buffer, \\[universal-argument] will give you a helm menu to
select a new link type for the selected entries.
A double \\[universal-argument] \\[universal-argument] will
change the key at point to the selected keys."
(let* ((object (org-element-context))
(last-char (save-excursion
(when (org-element-property :end object)
(goto-char (org-element-property :end object))
(unless (bobp)
(backward-char))
(if (looking-at " ")
" "
"")))))
(cond
;; case where we are in a link
((and (equal (org-element-type object) 'link)
(-contains?
org-ref-cite-types
(org-element-property :type object)))
(cond
;; no prefix. insert or append keys
((equal helm-current-prefix-arg nil)
(cond
;; point after :
((looking-back ":" (- (point) 2))
(insert (concat (mapconcat 'identity keys ",") ",")))
;; point on :
((looking-at ":")
(forward-char)
(insert (concat (mapconcat 'identity keys ",") ",")))
;; point on the cite type
((-contains? org-ref-cite-types (thing-at-point 'word))
(re-search-forward ":")
(insert (concat (mapconcat 'identity keys ",") ",")))
;; after ,
((looking-back "," (- (point) 2))
(insert (concat (mapconcat 'identity keys ",") ",")))
;; on comma
((looking-at ",")
(forward-char)
(insert (concat (mapconcat 'identity keys ",") ",")))
;; somewhere in the middle or end
(t
;; goto next comma or end
(re-search-forward
","
(org-element-property :end object) 'mv)
(skip-chars-backward " ")
(skip-chars-backward "]")
(unless (looking-at ",") (insert ","))
(insert (mapconcat 'identity keys ",")))))
;; double prefix, replace key at point
((equal helm-current-prefix-arg '(16))
(setf (buffer-substring
(org-element-property :begin object)
(org-element-property :end object))
(concat
(replace-regexp-in-string
(car (org-ref-get-bibtex-key-and-file)) ; key
(mapconcat 'identity keys ",") ; new keys
(org-element-property :raw-link object))
;; replace space at end to avoid collapsing into next word.
last-char))
;; and we want to go to the end of the new link
(goto-char
(org-element-property :end (org-element-context))))
(t
(message "Not found"))))
;; We are next to a link, and we want to append
;; next to a link means one character back is on a link.
((save-excursion
(unless (bobp) (backward-char))
(and (equal (org-element-type (org-element-context)) 'link)
(-contains?
org-ref-cite-types
(org-element-property :type (org-element-context)))))
(skip-chars-backward " ")
(insert (concat "," (mapconcat 'identity keys ","))))
;; insert fresh link
(t
(insert
(concat
(when org-ref-prefer-bracket-links "[[")
(if (equal helm-current-prefix-arg '(4))
(helm :sources `((name . "link types")
(candidates . ,org-ref-cite-types)
(action . (lambda (x) x))))
org-ref-default-citation-link)
":"
(s-join "," keys)
(when org-ref-prefer-bracket-links "]]"))))))
;; return empty string for helm
"")
(defun org-ref-format-citation (keys)
"Formatter for org-ref citation commands.
Prompt for the command and additional arguments if the commands can
take any. If point is inside a citation link, append KEYS. Otherwise
prompt for pre/post text. Prompts can also be switched off by setting
the variable `bibtex-completion-cite-prompt-for-optional-arguments' to
nil. To enable this formatter, add it to
`bibtex-completion-format-citation-functions'. For example:
\(setf (cdr (assoc 'org-mode bibtex-completion-format-citation-functions)) 'org-ref-format-citation)
Note also that pre text is preceded by a double colon, for example:
\[[cite:key][See::Chapter 1]], which exports to:
\\cite[See][Chapter 1]{key}."
;; Check if point is inside a cite link
(let ((link (org-element-context))
end path)
(if (-contains? org-ref-cite-types (org-element-property :type link))
(progn
(setq end (org-element-property :end link)
path (org-element-property :path link))
(goto-char end)
(skip-chars-backward " ")
;; Check if link has pre/post text
(if (looking-back "\]" (line-beginning-position))
(progn
(re-search-backward path nil t)
(re-search-forward "\]" nil t)
(backward-char 1)
(format ",%s" (s-join "," keys))))
(format ",%s" (s-join "," keys)))
(let* ((initial (when bibtex-completion-cite-default-as-initial-input bibtex-completion-cite-default-command))
(default
(unless bibtex-completion-cite-default-as-initial-input bibtex-completion-cite-default-command))
(default-info
(if default (format " (default \"%s\")" default) ""))
(cite-command
(completing-read (format "Cite command%s: " default-info)
bibtex-completion-cite-commands nil nil initial
'bibtex-completion-cite-command-history default nil)))
(if (member cite-command '("nocite" "supercite")) ; These don't want arguments.
(format "%s:%s" cite-command (s-join "," keys))
(let ((text (if bibtex-completion-cite-prompt-for-optional-arguments
(read-from-minibuffer "Pre/post text: ")
"")))
(if (string= "" text)
(format "%s:%s" cite-command (s-join "," keys))
(format "[[%s:%s][%s]]" cite-command (s-join "," keys) text))))))))
(defvar bibtex-completion-cached-candidates)
(defvar bibtex-completion-bibliography-hash)
;;;###autoload
(defun org-ref-helm-load-completions-async ()
"Load the bibtex files into helm sources asynchronously.
For large bibtex files, the initial call to org-ref-helm-insert-cite-link
can take a long time to load the completion sources. This function loads
the completion sources in the background so the initial call to org-ref-helm-insert-cite-link is much faster."
(interactive)
(async-start
`(lambda (&optional formatter)
(require 'package)
(package-initialize)
(require 'helm-bibtex)
,(async-inject-variables "bibtex-compl.*")
(with-temp-buffer
(mapc #'insert-file-contents
(-flatten (list bibtex-completion-bibliography)))
;; Check hash of bibliography and reparse if necessary:
(let ((bibliography-hash (secure-hash 'sha256 (current-buffer))))
(unless (and bibtex-completion-cached-candidates
(string= bibtex-completion-bibliography-hash bibliography-hash))
(message "Loading bibliography ...")
(let* ((entries (bibtex-completion-parse-bibliography))
(entries (bibtex-completion-resolve-crossrefs entries))
(entries (bibtex-completion-prepare-entries entries))
(entries (nreverse entries))
(entries
(--map (cons (bibtex-completion-clean-string
(s-join " " (-map #'cdr it))) it)
entries)))
(setq bibtex-completion-cached-candidates
(if (functionp formatter)
(funcall formatter entries)
entries)))
(setq bibtex-completion-bibliography-hash bibliography-hash))
(cons bibliography-hash bibtex-completion-cached-candidates))))
(lambda (result)
(setq bibtex-completion-cached-candidates (cdr result))
(setq bibtex-completion-bibliography-hash (car result))
(message "Finished loading org-ref completions"))))
;;;###autoload
(defun org-ref-helm-insert-cite-link (&optional arg)
"Insert a citation link with `helm-bibtex'.
With one prefix ARG, insert a ref link.
With two prefix ARGs, insert a label link."
(interactive "P")
;; save all bibtex buffers so we get the most up-to-date selection. I find
;; that I often edit a bibliography and forget to save it, so the newest entry
;; does not show in helm-bibtex.
(org-ref-save-all-bibtex-buffers)
(cond
((equal arg nil)
(let ((bibtex-completion-bibliography (org-ref-find-bibliography)))
(helm-bibtex)))
((equal arg '(4))
(org-ref-helm-insert-ref-link))
((equal arg '(16))
(org-ref-helm-insert-label-link))))
;; add our own fallback entries where we want them. These appear in reverse
;; order of adding in the menu
(setq bibtex-completion-fallback-options
(-insert-at 1 '("Crossref" . "http://search.crossref.org/?q=%s") bibtex-completion-fallback-options))
(setq bibtex-completion-fallback-options
(-insert-at
1
'("Scopus" . "http://www.scopus.com/scopus/search/submit/xadvanced.url?searchfield=TITLE-ABS-KEY(%s)")
bibtex-completion-fallback-options))
(setq bibtex-completion-fallback-options
(-insert-at 1 '("WOS" . "http://gateway.webofknowledge.com/gateway/Gateway.cgi?topic=%s&GWVersion=2&SrcApp=WEB&SrcAuth=HSB&DestApp=UA&DestLinkType=GeneralSearchSummary") bibtex-completion-fallback-options))
(defun org-ref-cite-candidates ()
"Generate the list of possible candidates for click actions on a cite link.
Checks for pdf and doi, and add appropriate functions."
(let* ((results (org-ref-get-bibtex-key-and-file))
(key (car results))
(bibfile (cdr results))
(bibtex-completion-bibliography (list bibfile))
(entry (bibtex-completion-get-entry key))
(pdf-file (funcall org-ref-get-pdf-filename-function key))
(pdf-bibtex-completion (car (bibtex-completion-find-pdf key)))
(notes-p (cdr (assoc "=has-note=" entry)))
(url (save-excursion
(with-temp-buffer
(insert-file-contents bibfile)
(bibtex-set-dialect (parsebib-find-bibtex-dialect) t)
(bibtex-search-entry key)
(bibtex-autokey-get-field "url"))))
(doi (save-excursion
(with-temp-buffer
(insert-file-contents bibfile)
(bibtex-set-dialect (parsebib-find-bibtex-dialect) t)
(bibtex-search-entry key)
;; I like this better than bibtex-url which does not always find
;; the urls
(bibtex-autokey-get-field "doi"))))
(candidates `(("Quit" . org-ref-citation-at-point)
("Open bibtex entry" . org-ref-open-citation-at-point))))
;; for some reason, when there is no doi or url, they are returned as "". I
;; prefer nil so we correct this here.
(when (string= doi "") (setq doi nil))
(when (string= url "") (setq url nil))
;; Conditional pdf functions
;; try with org-ref first
(cond ((file-exists-p pdf-file)
(cl-pushnew
'("Open pdf" . (lambda ()
(funcall org-ref-open-pdf-function)))
candidates))
;; try with bibtex-completion
(pdf-bibtex-completion
(cl-pushnew
'("Open pdf" . (lambda ()
(funcall org-ref-open-pdf-function)))
candidates))
;; try with doi
(t
(cl-pushnew
'("Try to get pdf" . (lambda ()
(save-window-excursion
(org-ref-open-citation-at-point)
(bibtex-beginning-of-entry)
(doi-utils-get-bibtex-entry-pdf))))
candidates)))
(if notes-p
(cl-pushnew
'("Open notes" . org-ref-open-notes-at-point)
candidates)
(cl-pushnew
'("Add notes" . org-ref-open-notes-at-point)
candidates))
;; conditional url and doi functions
(when (or url doi)
(cl-pushnew
'("Open in browser" . org-ref-open-url-at-point)
candidates))
(when doi
(mapc (lambda (x)
(cl-pushnew x candidates))
`(("WOS" . org-ref-wos-at-point)
("Related articles in WOS" . org-ref-wos-related-at-point)
("Citing articles in WOS" . org-ref-wos-citing-at-point)
("Google Scholar" . org-ref-google-scholar-at-point)
("Pubmed" . org-ref-pubmed-at-point)
("Crossref" . org-ref-crossref-at-point))))
(cl-pushnew
'("Insert new citation" . (lambda ()
(org-ref-helm-insert-cite-link nil)))
candidates)
(cl-pushnew
'("Delete key at point" . org-ref-delete-key-at-point)
candidates)
;; This is kind of clunky. We store the key at point. Add the new ref. Get
;; it off the end, and put it in the original position.
(cl-pushnew
'("Replace key at point" . org-ref-replace-key-at-point)
candidates)
(cl-pushnew
'("Delete citation at point" . org-ref-delete-cite-at-point)
candidates)
(when bibtex-completion-cite-prompt-for-optional-arguments
(cl-pushnew
'("Update pre/post text" . org-ref-update-pre-post-text)
candidates))
(cl-pushnew
'("Sort keys by year" . org-ref-sort-citation-link)
candidates)
(cl-pushnew
'("Copy formatted citation to clipboard" . org-ref-copy-cite-as-summary)
candidates)
(cl-pushnew
'("Copy key to clipboard" . (lambda ()
(kill-new
(car (org-ref-get-bibtex-key-and-file)))))
candidates)
(cl-pushnew
'("Copy bibtex entry to file" . org-ref-copy-entry-at-point-to-file)
candidates)
(cl-pushnew
'("Email bibtex entry and pdf" . (lambda ()
(save-excursion
(org-ref-open-citation-at-point)
(org-ref-email-bibtex-entry))))
candidates)
;; add Scopus functions. These work by looking up a DOI to get a Scopus
;; EID. This may only work for Scopus articles. Not all DOIs are recognized
;; in the Scopus API. We only load these if you have defined a
;; `*scopus-api-key*', which is required to do the API queries. See
;; `scopus'. These functions are appended to the candidate list.
(when (and (boundp '*scopus-api-key*) *scopus-api-key*)
(cl-pushnew
'("Open in Scopus" . (lambda ()
(let ((eid (scopus-doi-to-eid (org-ref-get-doi-at-point))))
(if eid
(scopus-open-eid eid)
(message "No EID found.")))))
candidates)
(cl-pushnew
'("Scopus citing articles" . (lambda ()
(let ((url (scopus-citing-url
(org-ref-get-doi-at-point))))
(if url
(browse-url url)
(message "No url found.")))))
candidates)
(cl-pushnew
'("Scopus related by authors" . (lambda ()
(let ((url (scopus-related-by-author-url
(org-ref-get-doi-at-point))))
(if url
(browse-url url)
(message "No url found.")))))
candidates)
(cl-pushnew
'("Scopus related by references" . (lambda ()
(let ((url (scopus-related-by-references-url
(org-ref-get-doi-at-point))))
(if url
(browse-url url)
(message "No url found.")))))
candidates)
(cl-pushnew
'("Scopus related by keywords" . (lambda ()
(let ((url (scopus-related-by-keyword-url
(org-ref-get-doi-at-point))))
(if url
(browse-url url)
(message "No url found.")))))
candidates))
;; finally return a numbered list of the candidates
(cl-loop for i from 0
for cell in (reverse candidates)
collect (cons (format "%2s. %s" i (car cell))
(cdr cell)))))
(defvar org-ref-helm-user-candidates '()
"List of user-defined candidates to act when clicking on a cite link.
This is a list of cons cells '((\"description\" . action)). The
action function should not take an argument, and should assume
point is on the cite key of interest.")
;; example of adding your own function
(add-to-list
'org-ref-helm-user-candidates
'("Open pdf in emacs" . (lambda ()
(find-file
(concat
(file-name-as-directory org-ref-pdf-directory)
(car (org-ref-get-bibtex-key-and-file))
".pdf"))))
t)
;;;###autoload
(defun org-ref-cite-click-helm (_key)
"Open helm for actions on a cite link.
subtle points.
1. get name and candidates before entering helm because we need
the org-buffer.
2. switch back to the org buffer before evaluating the
action. most of them need the point and buffer.
KEY is returned for the selected item(s) in helm."
(interactive)
(let ((name (org-ref-format-entry (org-ref-get-bibtex-key-under-cursor)))
(candidates (org-ref-cite-candidates))
(cb (current-buffer)))
(helm :sources `(((name . ,name)
(candidates . ,candidates)
(action . (lambda (f)
(switch-to-buffer ,cb)
(funcall f))))
((name . "User functions")
(candidates . ,org-ref-helm-user-candidates)
(action . (lambda (f)
(switch-to-buffer ,cb)
(funcall f))))))))
;; browse labels
(defun org-ref-browser-label-source ()
(let ((labels (org-ref-get-labels)))
(helm-build-sync-source "Browse labels"
:follow 1
:candidates labels
:action '(("Browse labels" . (lambda (label)
(with-selected-window (selected-window)
(org-open-link-from-string
(format "ref:%s" label)))))))))
;; browse citation links
(defun org-ref-browser-transformer (candidates)
"Add counter to candidates."
(let ((counter 0))
(cl-loop for i in candidates
collect (format "%s %s" (cl-incf counter) i))))
(defun org-ref-browser-display (candidate)
"Strip counter from candidates."
(replace-regexp-in-string "^[0-9]+? " "" candidate))
;;;###autoload
(defun org-ref-browser (&optional arg)
"Quickly browse label links in helm.
With a prefix ARG, browse citation links."
(interactive "P")
(if arg
(let ((keys nil)
(alist nil))
(widen)
(outline-show-all)
(org-element-map (org-element-parse-buffer) 'link
(lambda (link)
(let ((plist (nth 1 link)))
(when (-contains? org-ref-cite-types (plist-get plist ':type))
(let ((start (org-element-property :begin link)))
(dolist (key
(org-ref-split-and-strip-string (plist-get plist ':path)))
(setq keys (append keys (list key)))
(setq alist (append alist (list (cons key start))))))))))
(let ((counter 0)
count-key-pos)
;; the idea here is to create an alist with ("counter key" .
;; position) to produce unique candidates
(setq count-key-pos (mapcar (lambda (x)
(cons
(format "%s %s" (cl-incf counter) (car x)) (cdr x)))
alist))
;; push mark to restore position with C-u C-SPC
(push-mark (point))
;; move point to the first citation link in the buffer
(goto-char (cdr (assoc (caar alist) alist)))
(helm :sources
(helm-build-sync-source "Browse citation links"
:follow 1
:candidates keys
:candidate-transformer 'org-ref-browser-transformer
:real-to-display 'org-ref-browser-display
:persistent-action (lambda (candidate)
(helm-goto-char
(cdr (assoc candidate count-key-pos))))
:action `(("Open menu" . ,(lambda (candidate)
(helm-goto-char
(cdr (assoc candidate count-key-pos)))
(org-open-at-point)))))
:candidate-number-limit 10000
:buffer "*helm browser*")))
(helm :sources (org-ref-browser-label-source)
:buffer "*helm labels*")))
(provide 'org-ref-helm-bibtex)
;;; org-ref-helm-bibtex.el ends here

View File

@@ -1,771 +0,0 @@
;;; org-ref-helm-cite.el --- Helm interface to insert citations from bibtex files for org-ref -*- lexical-binding: t; -*-
;; Copyright (C) 2016 John Kitchin
;; Author: John Kitchin <jkitchin@andrew.cmu.edu>
;; Keywords:
;; 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 <http://www.gnu.org/licenses/>.
;;; Commentary: This is a competitor of `helm-bibtex'.
;; The main difference is the format of the candidates, which are full citations
;; in this package, and multiline. This package also makes the candidates
;; sortable in different ways, and provides different, context specific actions
;; depending on what buffer you call `org-ref-helm-cite' from, and depending
;; on the properties of the selected candidate.
;;
;; Another significant feature is persistent caching of bibtex files to make
;; startup fast.
;;
(declare-function 'org-ref-find-bibliography "org-ref-core.el")
(declare-function 'org-ref-get-bibtex-key-and-file "org-ref-core.el")
(defvar org-ref-pdf-directory)
(defvar org-ref-notes-directory)
(defvar org-ref-cite-types)
(defvar org-ref-default-citation-link)
(defvar org-ref-insert-link-function)
(defvar org-ref-insert-cite-function)
(defvar org-ref-insert-label-function)
(defvar org-ref-insert-ref-function)
(defvar org-ref-cite-onclick-function)
(defvar org-ref-insert-cite-key)
;;; Code:
(require 'org-ref-helm)
(require 'org-ref-bibtex)
(defun org-ref-helm-cite-completion ()
"Use helm and org-ref for completion."
(interactive)
(setq org-ref-insert-link-function 'org-ref-insert-link
org-ref-insert-cite-function 'org-ref-helm-cite
org-ref-insert-label-function 'org-ref-helm-insert-label-link
org-ref-insert-ref-function 'org-ref-helm-insert-ref-link
org-ref-cite-onclick-function 'org-ref-helm-cite-click))
(org-ref-helm-cite-completion)
(define-key org-mode-map
(kbd org-ref-insert-cite-key)
org-ref-insert-link-function)
;;* Variables
(defvar org-ref-helm-cite-from nil
"Variable to store the mode `org-ref-helm-cite' was called
from. This is used to provide some context specific actions.")
(defvar org-ref-helm-cite-help-message
"* Org-ref helm bibtex.
M-<down> allows you to sort the entries by year or first author
last name.")
(defvar org-ref-helm-cite-map
(let ((map (make-sparse-keymap)))
(set-keymap-parent map helm-map)
(define-key map (kbd "M-<down>") 'org-ref-helm-cite-sort)
map))
(defvar orhc-sort-fn nil
"Function for sorting the helm entries.")
;;* Helm functions
(defun orhc-helm-cite-sort-alphabetical-a (c1 c2)
"Sort entries by first author last name from a to z."
(let* ((a1 (cdr c1))
(au1 (cdr (assoc "author" a1)))
(a2 (cdr c2))
(au2 (cdr (assoc "author" a2)))
fa1 fa2)
(if (or (not (stringp au1))
(not (stringp au2)))
nil
;; we need to parse names
(setq fa1 (car (s-split " and " au1))
fa2 (car (s-split " and " au2)))
(if (string-match "," fa1)
;; last, first
(setq fa1 (car (s-split "," fa1)))
;; first last, ignore von names and jr
(setq fa1 (car (last (s-split " " fa1)))))
(if (string-match "," fa2)
;; last, first
(setq fa2 (car (s-split "," fa2)))
;; first last, ignore von names, and jr
(setq fa2 (car (last (s-split " " fa2)))))
(string< fa1 fa2))))
(defun orhc-helm-cite-sort-alphabetical-z (c1 c2)
"Sort entries by first author last name from z to a."
(let* ((a1 (cdr c1))
(au1 (cdr (assoc "author" a1)))
(a2 (cdr c2))
(au2 (cdr (assoc "author" a2)))
fa1 fa2)
(if (or (not (stringp au1))
(not (stringp au2)))
nil
;; we need to parse names to get lastname
(setq fa1 (car (s-split " and " au1))
fa2 (car (s-split " and " au2)))
(if (string-match "," fa1)
;; last, first
(setq fa1 (car (s-split "," fa1)))
;; first last, ignore von names and jr
(setq fa1 (car (last (s-split " " fa1)))))
(if (string-match "," fa2)
;; last, first
(setq fa2 (car (s-split "," fa2)))
;; first last, ignore von names, and jr
(setq fa2 (car (last (s-split " " fa2)))))
(string< fa2 fa1))))
(defun org-ref-helm-cite-sort ()
"Sort interface for `org-ref-helm-cite'."
(interactive)
(let ((action (read-char "year↓ (y) year↑ (Y)
1st author↓ (a) 1st author↑ (z)
key↓ (k) key↑ (K): ")))
(cond
;; sort on year
((eq action ?y)
(setq orhc-sort-fn
(lambda (c1 c2)
(let* ((a1 (cdr c1))
(y1 (cdr (assoc "year" a1)))
(a2 (cdr c2))
(y2 (cdr (assoc "year" a2))))
(if (or (null y1) (null y2))
nil
(> (string-to-number y1) (string-to-number y2)))))))
((eq action ?Y)
(setq orhc-sort-fn
(lambda (c1 c2)
(let* ((a1 (cdr c1))
(y1 (cdr (assoc "year" a1)))
(a2 (cdr c2))
(y2 (cdr (assoc "year" a2))))
(if (or (null y1) (null y2))
nil
(< (string-to-number y1) (string-to-number y2)))))))
;; sort on key
((eq action ?k)
(setq orhc-sort-fn
(lambda (c1 c2)
(let* ((a1 (cdr c1))
(k1 (cdr (assoc "=key=" a1)))
(a2 (cdr c2))
(k2 (cdr (assoc "=key=" a2))))
(string< k2 k1)))))
((eq action ?K)
(setq orhc-sort-fn
(lambda (c1 c2)
(let* ((a1 (cdr c1))
(k1 (cdr (assoc "=key=" a1)))
(a2 (cdr c2))
(k2 (cdr (assoc "=key=" a2))))
(string< k1 k2)))))
;; sort on first author last name
((eq action ?a)
(setq orhc-sort-fn #'orhc-helm-cite-sort-alphabetical-a))
((eq action ?z)
(setq orhc-sort-fn #'orhc-helm-cite-sort-alphabetical-z))
(t (setq orhc-sort-fn nil)))
(helm-update)
(setq orhc-sort-fn nil)))
(defun org-ref-helm-candidate-transformer (candidates _source)
"Transform CANDIDATES, sorting if needed.
SOURCE is ignored, but required."
(if orhc-sort-fn
(-sort orhc-sort-fn candidates)
candidates))
(defun org-ref-helm-cite-action-transformer (actions candidate)
"Compute ACTIONS for CANDIDATE."
;; Check for pdf and add open or get action.
(setq actions (append
actions
'(("insert citation(s)" . org-ref-helm-cite-insert-citation)
("show entry" . org-ref-helm-cite-open-entry))))
(let ((pdf (expand-file-name
(concat (cdr (assoc "=key=" candidate)) ".pdf")
org-ref-pdf-directory)))
(if (file-exists-p pdf)
(setq actions (append actions
(list
(cons
(format "Open %s" pdf)
(lambda (_candidate)
(org-open-file pdf))))))
(when (assoc "doi" candidate)
(setq actions
(append actions
(list
(cons
(format "Get PDF")
(lambda (candidate)
(save-window-excursion
(find-file (cdr (assoc "file" candidate)))
(goto-char (cdr (assoc "position" candidate)))
(doi-utils-get-bibtex-entry-pdf))))))))))
;; check for url/doi
(when (assoc "url" candidate)
(setq actions (append actions
(list
(cons (format "Open %s"
(cdr (assoc "url" candidate)))
(lambda (x)
(browse-url (cdr (assoc "url" x)))))))))
(when (assoc "doi" candidate)
(setq actions (append actions
(list
(cons
(format "Open doi (%s)"
(cdr (assoc "doi" candidate)))
(lambda (x)
(browse-url
(format "http://dx.doi.org/%s"
(cdr (assoc "doi" x))))))))))
;; Notes, open or create.
(let ((note-file (expand-file-name
(concat (cdr (assoc "=key=" candidate)) ".org")
org-ref-notes-directory)))
(if (file-exists-p note-file)
(setq actions (append actions (list (cons "Open notes"
(lambda (_x)
(find-file note-file))))))
(setq actions (append actions (list (cons "Create notes"
(lambda (_x)
(find-file note-file))))))))
(setq actions (append
actions
'(("Add keywords" . org-ref-helm-cite-set-keywords)
("copy to clipboard" . org-ref-helm-cite-copy-entries)
("email" . org-ref-helm-cite-email-entries)
("Insert formatted entries" . (lambda (_)
(insert
(mapconcat 'identity
(cl-loop for key in (helm-marked-candidates)
collect (org-ref-format-entry key))
"\n\n"))))
("Copy formatted entry" . (lambda (_)
(kill-new
(mapconcat 'identity
(cl-loop for key in (helm-marked-candidates)
collect (org-ref-format-entry key))
"\n\n")))))))
;; this is where we could add WOK/scopus functions
actions)
(defun org-ref-helm-cite-insert-citation (_candidate)
"Insert selected CANDIDATE as cite link.
This is an action for helm, and it actually works on
`helm-marked-candidates'. Append KEYS if you are on a link.
In the `org-ref-helm-cite' buffer, \\[universal-argument] will give you
a helm menu to select a new link type for the selected entries.
A double \\[universal-argument] \\[universal-argument] will
change the key at point to the selected keys."
(let* ((keys (cl-loop for entry in (helm-marked-candidates)
collect (cdr (assoc "=key=" entry))))
(object (org-element-context))
(last-char (save-excursion
(when (org-element-property :end object)
(goto-char (org-element-property :end object))
(unless (bobp)
(backward-char))
(if (looking-at " ")
" "
"")))))
(cond
;; case where we are in a link
((and (equal (org-element-type object) 'link)
(-contains?
org-ref-cite-types
(org-element-property :type object)))
(cond
;; no prefix. insert or append keys
((equal helm-current-prefix-arg nil)
(cond
;; point after :
((looking-back ":" (- (point) 2))
(insert (concat (mapconcat 'identity keys ",") ",")))
;; point on :
((looking-at ":")
(forward-char)
(insert (concat (mapconcat 'identity keys ",") ",")))
;; point on the cite type
((-contains? org-ref-cite-types (thing-at-point 'word))
(re-search-forward ":")
(insert (concat (mapconcat 'identity keys ",") ",")))
;; after ,
((looking-back "," (- (point) 2))
(insert (concat (mapconcat 'identity keys ",") ",")))
;; on comma
((looking-at ",")
(forward-char)
(insert (concat (mapconcat 'identity keys ",") ",")))
;; somewhere in the middle or end
(t
;; goto next comma or end
(re-search-forward
","
(org-element-property :end object) t)
(skip-chars-backward " ")
(insert (mapconcat 'identity keys ","))
(unless (looking-at ",") (insert ",")))))
;; double prefix, replace key at point
((equal helm-current-prefix-arg '(16))
(setf (buffer-substring
(org-element-property :begin object)
(org-element-property :end object))
(concat
(replace-regexp-in-string
(car (org-ref-get-bibtex-key-and-file)) ; key
(mapconcat 'identity keys ",") ; new keys
(org-element-property :raw-link object))
;; replace space at end to avoid collapsing into next word.
last-char))
;; and we want to go to the end of the new link
(goto-char
(org-element-property :end (org-element-context))))
(t
(message "Not found"))))
;; We are next to a link, and we want to append
;; next to a link means one character back is on a link.
((save-excursion
(unless (bobp) (backward-char))
(and (equal (org-element-type (org-element-context)) 'link)
(-contains?
org-ref-cite-types
(org-element-property :type (org-element-context)))))
(skip-chars-backward " ")
(insert (concat "," (mapconcat 'identity keys ","))))
;; insert fresh link
(t
;;(message-box "fresh link")
(insert
(concat (if (equal helm-current-prefix-arg '(4))
(helm :sources `((name . "link types")
(candidates . ,org-ref-cite-types)
(action . (lambda (x) x))))
org-ref-default-citation-link)
":"
(s-join "," keys)))))))
(defun org-ref-helm-cite-init ()
"Initializes the source, setting bibtex files from the
originating buffer, and mode of originating buffer."
(org-ref-save-all-bibtex-buffers)
(setq org-ref-bibtex-files (org-ref-find-bibliography))
;; save major-mode we came from so we can do context specific things.
(setq org-ref-helm-cite-from major-mode)
(message "initialized."))
(defun org-ref-helm-cite-open-entry (entry)
"Open the selected bibtex entry in its file."
(find-file (cdr (assoc "bibfile" entry)))
(goto-char (cdr (assoc "position" entry)))
(bibtex-beginning-of-entry))
(defun org-ref-helm-cite-copy-entries (_candidate)
"Copy selected bibtex entries to the clipboard."
(with-temp-buffer
(cl-loop for entry in (helm-marked-candidates)
do
(save-window-excursion
(org-ref-helm-cite-open-entry entry)
(bibtex-copy-entry-as-kill))
(bibtex-yank)
(insert "\n"))
(kill-region (point-min) (point-max))))
(defun org-ref-helm-cite-email-entries (_candidate)
"Insert selected entries and attach pdf files to an email.
Create email unless called from an email."
(unless (or (eq org-ref-helm-cite-from 'message-mode)
(eq org-ref-helm-cite-from 'mu4e-compose-mode))
(compose-mail))
(cl-loop for entry in (helm-marked-candidates)
do
(save-window-excursion
(org-ref-helm-cite-open-entry entry)
(bibtex-copy-entry-as-kill))
(message-goto-body)
(insert (pop bibtex-entry-kill-ring))
(insert "\n")
if (file-exists-p (expand-file-name
(concat (cdr (assoc "=key=" entry)) ".pdf")
org-ref-pdf-directory))
do
(mml-attach-file (expand-file-name
(concat (cdr (assoc "=key=" entry)) ".pdf")
org-ref-pdf-directory)))
(message-goto-to))
(defun org-ref-helm-cite-set-keywords (_candidate)
"Prompt for keywords, and put them on the selected entries."
(let ((keywords (read-string "Keyword(s) comma-separated: " ))
entry-keywords)
(cl-loop for entry in (helm-marked-candidates)
do
(save-window-excursion
(org-ref-helm-cite-open-entry entry)
(setq entry-keywords (bibtex-autokey-get-field "keywords"))
(bibtex-set-field
"keywords"
(if (> (length entry-keywords) 0)
(concat entry-keywords ", " keywords)
keywords))))))
;;** Helm sources
(defvar orhc-multiline t
"Make helm-source multiline if non-nil.
This adds a small separator between the candidates which is a
little more readable.")
(defvar org-ref-helm-user-candidates '()
"List of user-defined candidates to act when clicking on a cite link.
This is a list of cons cells '((\"description\" . action)). The
action function should not take an argument, and should assume
point is on the cite key of interest.")
(defvar org-ref-helm-cite-source
(helm-build-sync-source "org-ref Bibtex"
:init #'org-ref-helm-cite-init
:candidates #'orhc-bibtex-candidates
:keymap 'org-ref-helm-cite-map
:multiline orhc-multiline
:help-message 'org-ref-helm-cite-help-message
:filtered-candidate-transformer 'org-ref-helm-candidate-transformer
:action-transformer 'org-ref-helm-cite-action-transformer
:action '()))
;; Fallback sources
;; The candidates here are functions that work on `helm-pattern'.
(defvar org-ref-helm-cite-fallback-source
nil
"Helm fallback source.")
(setq org-ref-helm-cite-fallback-source
(helm-build-sync-source "org-ref bibtex Fallbacks"
:candidates '(("Google" . (lambda ()
(browse-url
(format "http://www.google.com/search?q=%s"
(url-hexify-string helm-pattern)))))
("Google Scholar" . (lambda ()
(browse-url
(format "http://scholar.google.com/scholar?q=%s"
(url-hexify-string helm-pattern)))))
("Crossref" . (lambda ()
(browse-url
(format
"http://search.crossref.org/?q=%s"
(url-hexify-string helm-pattern)))))
("Pubmed" . (lambda ()
(browse-url
(format
"http://www.ncbi.nlm.nih.gov/pubmed/?term=%s"
(url-hexify-string helm-pattern)))))
("Arxiv" . (lambda ()
(browse-url
(format
"http://arxiv.org/find/all/1/all:+AND+%s/0/1/0/all/0/1"
(url-hexify-string helm-pattern)))))
("WebOfKnowledge" . (lambda ()
(browse-url
(format
"http://gateway.webofknowledge.com/gateway/Gateway.cgi?topic=%s&GWVersion=2&SrcApp=WEB&SrcAuth=HSB&DestApp=UA&DestLinkType=GeneralSearchSummary"
(url-hexify-string helm-pattern)))))
("Scopus" . (lambda ()
(browse-url
(format
"http://www.scopus.com//search/submit/basic.url?field1=TITLE-ABS-KEY&searchterm1=%s"
(url-hexify-string helm-pattern)))))
)
;; This keeps all the fallback candidates available, by tricking it into
;; thinking every candidate is a match.
:match (lambda (_candidate) t)
:action (lambda (candidate) (funcall candidate))))
(defun org-ref-helm-cite ()
"Helm interface to bibtex files for `org-ref'."
(interactive)
(helm :sources '(org-ref-helm-cite-source
org-ref-helm-cite-fallback-source)))
(defalias 'orhc 'org-ref-helm-cite)
;; ** Onclick function
;; These are adapted from org-ref-helm-bibtex, and the dependencies on helm-bibtex removed.
(defun org-ref-helm-cite-candidates ()
"Generate the list of possible candidates for click actions on a cite link.
Checks for pdf and doi, and add appropriate functions."
(let* ((results (org-ref-get-bibtex-key-and-file))
(key (car results))
(bibfile (cdr results))
(pdf-file (funcall org-ref-get-pdf-filename-function key))
(url (save-excursion
(with-temp-buffer
(insert-file-contents bibfile)
(bibtex-set-dialect (parsebib-find-bibtex-dialect) t)
(bibtex-search-entry key)
(bibtex-autokey-get-field "url"))))
(doi (save-excursion
(with-temp-buffer
(insert-file-contents bibfile)
(bibtex-set-dialect (parsebib-find-bibtex-dialect) t)
(bibtex-search-entry key)
;; I like this better than bibtex-url which does not always find
;; the urls
(bibtex-autokey-get-field "doi"))))
(candidates `(("Quit" . org-ref-citation-at-point)
("Open bibtex entry" . org-ref-open-citation-at-point))))
;; for some reason, when there is no doi or url, they are returned as "". I
;; prefer nil so we correct this here.
(when (string= doi "") (setq doi nil))
(when (string= url "") (setq url nil))
;; Conditional pdf functions
;; try with org-ref first
(cond ((file-exists-p pdf-file)
(cl-pushnew
'("Open pdf" . (lambda ()
(funcall org-ref-open-pdf-function)))
candidates))
;; try with doi
(t
(cl-pushnew
'("Try to get pdf" . (lambda ()
(save-window-excursion
(org-ref-open-citation-at-point)
(bibtex-beginning-of-entry)
(doi-utils-get-bibtex-entry-pdf))))
candidates)))
(cl-pushnew
'("Add/Open notes" . org-ref-open-notes-at-point)
candidates)
;; conditional url and doi functions
(when (or url doi)
(cl-pushnew
'("Open in browser" . org-ref-open-url-at-point)
candidates))
(when doi
(mapc (lambda (x)
(cl-pushnew x candidates))
`(("WOS" . org-ref-wos-at-point)
("Related articles in WOS" . org-ref-wos-related-at-point)
("Citing articles in WOS" . org-ref-wos-citing-at-point)
("ADS" . org-ref-ads-at-point)
("Google Scholar" . org-ref-google-scholar-at-point)
("Pubmed" . org-ref-pubmed-at-point)
("Crossref" . org-ref-crossref-at-point))))
(cl-pushnew
'("Insert new citation" . (lambda ()
(org-ref-helm-insert-cite-link nil)))
candidates)
(cl-pushnew
'("Delete key at point" . org-ref-delete-key-at-point)
candidates)
;; This is kind of clunky. We store the key at point. Add the new ref. Get
;; it off the end, and put it in the original position.
(cl-pushnew
'("Replace key at point" . org-ref-replace-key-at-point)
candidates)
(cl-pushnew
'("Delete citation at point" . org-ref-delete-cite-at-point)
candidates)
(cl-pushnew
'("Sort keys by year" . org-ref-sort-citation-link)
candidates)
(cl-pushnew
'("Copy formatted citation to clipboard" . org-ref-copy-entry-as-summary)
candidates)
(cl-pushnew
'("Copy key to clipboard" . (lambda ()
(kill-new
(car (org-ref-get-bibtex-key-and-file)))))
candidates)
(cl-pushnew
'("Copy bibtex entry to file" . org-ref-copy-entry-at-point-to-file)
candidates)
(cl-pushnew
'("Email bibtex entry and pdf" . (lambda ()
(save-excursion
(org-ref-open-citation-at-point)
(org-ref-email-bibtex-entry))))
candidates)
;; add Scopus functions. These work by looking up a DOI to get a Scopus
;; EID. This may only work for Scopus articles. Not all DOIs are recognized
;; in the Scopus API. We only load these if you have defined a
;; `*scopus-api-key*', which is required to do the API queries. See
;; `scopus'. These functions are appended to the candidate list.
(when (and (boundp '*scopus-api-key*) *scopus-api-key*)
(cl-pushnew
'("Open in Scopus" . (lambda ()
(let ((eid (scopus-doi-to-eid (org-ref-get-doi-at-point))))
(if eid
(scopus-open-eid eid)
(message "No EID found.")))))
candidates)
(cl-pushnew
'("Scopus citing articles" . (lambda ()
(let ((url (scopus-citing-url
(org-ref-get-doi-at-point))))
(if url
(browse-url url)
(message "No url found.")))))
candidates)
(cl-pushnew
'("Scopus related by authors" . (lambda ()
(let ((url (scopus-related-by-author-url
(org-ref-get-doi-at-point))))
(if url
(browse-url url)
(message "No url found.")))))
candidates)
(cl-pushnew
'("Scopus related by references" . (lambda ()
(let ((url (scopus-related-by-references-url
(org-ref-get-doi-at-point))))
(if url
(browse-url url)
(message "No url found.")))))
candidates)
(cl-pushnew
'("Scopus related by keywords" . (lambda ()
(let ((url (scopus-related-by-keyword-url
(org-ref-get-doi-at-point))))
(if url
(browse-url url)
(message "No url found.")))))
candidates))
;; finally return a numbered list of the candidates
(cl-loop for i from 0
for cell in (reverse candidates)
collect (cons (format "%2s. %s" i (car cell))
(cdr cell)))))
(defun org-ref-helm-cite-click (_key)
"Open helm for actions on a cite link.
subtle points.
1. get name and candidates before entering helm because we need
the org-buffer.
2. switch back to the org buffer before evaluating the
action. most of them need the point and buffer.
KEY is returned for the selected item(s) in helm."
(interactive)
(let ((name (org-ref-format-entry (org-ref-get-bibtex-key-under-cursor)))
(candidates (org-ref-helm-cite-candidates))
(cb (current-buffer)))
(helm :sources `(((name . ,name)
(candidates . ,candidates)
(action . (lambda (f)
(switch-to-buffer ,cb)
(funcall f))))
((name . "User functions")
(candidates . ,org-ref-helm-user-candidates)
(action . (lambda (f)
(switch-to-buffer ,cb)
(funcall f))))))))
;;* Formatted citations
(defun orhc-formatted-citations (_candidate)
"Return string containing formatted citations for entries in
`helm-marked-candidates'."
(load-library
(completing-read "Style: " '("unsrt" "author-year") nil nil "unsrt"))
(with-temp-buffer
(cl-loop for i from 1 to (length (helm-marked-candidates))
for entry in (helm-marked-candidates)
do
(insert (format "%s. %s\n\n" i (orhc-formatted-citation entry))))
(buffer-string)))
(defun orhc-insert-formatted-citations (candidate)
"Insert formatted citations at point for selected entries."
(insert (orhc-formatted-citations candidate)))
(defun orhc-copy-formatted-citations (candidate)
"Copy formatted citations to clipboard for selected entries."
(with-temp-buffer
(orhc-insert-formatted-citations candidate)
(kill-ring-save (point-min) (point-max))))
(provide 'org-ref-helm-cite)
;;; org-ref-helm-cite.el ends here

View File

@@ -1,473 +1,111 @@
;;; org-ref-helm.el --- Generic helm functions for org-ref -*- lexical-binding: t; -*-
;;; org-ref-helm.el --- org-ref interface to helm-bibtex -*- lexical-binding: t; -*-
;; Copyright (C) 2016 John Kitchin
;; Copyright(C) 2014-2016 John Kitchin
;; Author: John Kitchin <jkitchin@andrew.cmu.edu>
;; Keywords:
;; URL: https://github.com/jkitchin/org-ref
;; Version: 1.0
;; Keywords: org-mode, cite, ref, label
;; Package-Requires: ((helm-bibtex "0") (org-ref "0"))
;; 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 file is not currently part of GNU Emacs.
;; 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.
;; 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 2, 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 <http://www.gnu.org/licenses/>.
;; along with this program ; see the file COPYING. If not, write to
;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
;;; Commentary:
;;
;; Adapted from helm-bibtex, mostly so you get the default action to insert a citation
;; These are not specific to helm-bibtex.
(require 'org-ref-core)
(require 'helm-bibtex)
(defvar helm-bibtex-local-bib) ; to quiet compiler.
;;; Code:
(declare-function 'org-ref-get-bibtex-key-and-file "org-ref-core.el")
(declare-function 'org-ref-bad-file-link-candidates "org-ref-core.el")
(declare-function 'org-ref-get-labels "org-ref-core.el")
(declare-function 'org-ref-bad-cite-candidates "org-ref-core.el")
(declare-function 'org-ref-bad-ref-candidates "org-ref-core.el")
(declare-function 'org-ref-bad-label-candidates "org-ref-core.el")
(helm-bibtex-helmify-action org-ref-insert-cite-keys org-ref-helm-bibtex-insert-citation)
(require 'helm)
(require 'org-element)
(require 'org-ref-core)
(defvar org-ref-helm-source-bibtex
(helm-build-sync-source "BibTeX entries"
:header-name (lambda (name)
(format "%s%s: " name (if helm-bibtex-local-bib " (local)" "")))
:candidates 'helm-bibtex-candidates
:filtered-candidate-transformer 'helm-bibtex-candidates-formatter
:action (helm-make-actions
"Insert citation" 'org-ref-helm-bibtex-insert-citation
"Insert reference" 'helm-bibtex-insert-reference
"Open PDF, URL or DOI" 'helm-bibtex-open-any
"Open URL or DOI in browser" 'helm-bibtex-open-url-or-doi
"Insert BibTeX key" 'helm-bibtex-insert-key
"Insert BibTeX entry" 'helm-bibtex-insert-bibtex
"Attach PDF to email" 'helm-bibtex-add-PDF-attachment
"Edit notes" 'helm-bibtex-edit-notes
"Show entry" 'helm-bibtex-show-entry
"Add PDF to library" 'helm-bibtex-add-pdf-to-library))
"Source for searching in BibTeX files.")
(defvar org-ref-helm-source-fallback-options
'((name . "Fallback options")
(match (lambda (_candidate) t))
(candidates . bibtex-completion-fallback-candidates)
(no-matchplugin)
(nohighlight)
(action . (lambda (candidate) (bibtex-completion-fallback-action candidate helm-pattern))))
"Source for online look-up.")
;; Helm-bibtex command:
;;;###autoload
(defun org-ref-helm-insert-label-link ()
"Insert label link at point.
Helm will display existing labels in the current buffer to avoid
duplication. If you use a prefix arg insert a radio target
instead of a label."
(interactive)
(let ((labels (org-ref-get-labels)))
(helm :sources `(,(helm-build-sync-source "Existing labels"
:candidates labels
:action (lambda (label)
(with-helm-current-buffer
(org-open-link-from-string
(format "ref:%s" label)))))
,(helm-build-dummy-source "Create new label"
:action (lambda (label)
(with-helm-current-buffer
(if helm-current-prefix-arg
(insert (concat "<<" label ">>"))
(insert (concat "label:" label)))))))
:buffer "*helm labels*")))
(defun org-ref-cite-insert-helm (&optional arg local-bib input)
"Search BibTeX entries.
With a prefix ARG, the cache is invalidated and the bibliography
reread.
;;;###autoload
(defun org-ref-helm-insert-ref-link ()
"Helm menu to insert ref links to labels in the document.
If you are on link, replace with newly selected label. Use
\\[universal-argument] to insert a different kind of ref link.
Use a double \\[universal-argument] \\[universal-argument] to insert a
[[#custom-id]] link"
(interactive)
(let* ((labels (org-ref-get-labels))
(contexts (mapcar 'org-ref-get-label-context labels))
(cb (current-buffer)))
If LOCAL-BIB is non-nil, display that the BibTeX entries are read
from the local bibliography. This is set internally by
`helm-bibtex-with-local-bibliography'.
(helm :input (thing-at-point 'word)
:sources `(((name . "Available labels to ref")
(multiline)
(candidates . ,(cl-loop for label in labels
for context in contexts
;; we do some kludgy adding spaces
;; and bars to make it "easier" to
;; see in helm.
collect (cons (concat
label "\n"
(mapconcat
(lambda (x)
(concat " |" x))
(split-string context "\n")
"\n"
) "\n\n") label)))
;; default action to replace or insert ref link.
(action . (lambda (label)
(switch-to-buffer ,cb)
If INPUT is non-nil and a string, that value is going to be used
as a predefined search term. Can be used to define functions for
frequent searches (e.g. your own publications)."
(interactive "P")
(when arg
(bibtex-completion-clear-cache))
(bibtex-completion-init)
(let* ((candidates (bibtex-completion-candidates))
(key (bibtex-completion-key-at-point))
(preselect (and key
(cl-position-if (lambda (cand)
(member (cons "=key=" key)
(cdr cand)))
candidates))))
(helm :sources (list org-ref-helm-source-bibtex org-ref-helm-source-fallback-options)
:full-frame helm-bibtex-full-frame
:buffer "*helm bibtex*"
:input input
:preselect (lambda ()
(and preselect
(> preselect 0)
(helm-next-line preselect)))
:candidate-number-limit (max 500 (1+ (or preselect 0)))
:bibtex-candidates candidates
:bibtex-local-bib local-bib)))
(cond
;; no prefix or on a link
((equal helm-current-prefix-arg nil)
(let* ((object (org-element-context))
(last-char
(save-excursion
(goto-char (org-element-property :end object))
(backward-char)
(if (looking-at " ")
" "
""))))
(if (-contains? org-ref-ref-types
(org-element-property :type object))
;; we are on a link, so replace it.
(setf
(buffer-substring
(org-element-property :begin object)
(org-element-property :end object))
(concat
(replace-regexp-in-string
(org-element-property :path object)
label
(org-element-property :raw-link object))
last-char))
;; insert a new link
(insert
(concat
(org-ref-infer-ref-type label) ":" label))
)))
;; one prefix, alternate ref link
((equal helm-current-prefix-arg '(4))
(insert
(concat
(helm :sources `((name . "Ref link types")
(candidates . ,org-ref-ref-types)
(action . (lambda (x) x))))
":" label)))
;; two prefixes, insert section custom-id link
((equal helm-current-prefix-arg '(16))
(insert
(format "[[#%s]]" label)))))))))))
;;;###autoload
(defun org-ref-helm ()
"Opens a helm interface to actions for `org-ref'.
Shows bad citations, ref links and labels.
This widens the file so that all links go to the right place."
(interactive)
;; (widen)
;; (org-cycle '(64))
(let ((cb (current-buffer))
(bad-citations (org-ref-bad-cite-candidates))
(bad-refs (org-ref-bad-ref-candidates))
(bad-labels (org-ref-bad-label-candidates))
(bad-files (org-ref-bad-file-link-candidates))
(bib-candidates '())
(unreferenced-labels '())
natbib-required
natbib-used
cleveref-required
cleveref-used
biblatex-required
biblatex-used
(org-latex-prefer-user-labels (and (boundp 'org-latex-prefer-user-labels)
org-latex-prefer-user-labels)))
;; See if natbib, biblatex or cleveref are required
(org-element-map (org-element-parse-buffer) 'link
(lambda (link)
(when (member (org-element-property :type link) org-ref-natbib-types)
(setq natbib-required t))
(when (member (org-element-property :type link) org-ref-biblatex-types)
(setq biblatex-required t))
(when (member (org-element-property :type link) '("cref" "Cref"))
(setq cleveref-required t)))
nil t)
;; See if natbib is probably used. This will miss a case where natbib is included somehow.
(setq natbib-used
(or
(member "natbib" (mapcar (lambda (x) (when (listp x) (nth 1 x))) org-latex-default-packages-alist))
(member "natbib" (mapcar (lambda (x) (when (listp x) (nth 1 x))) org-latex-packages-alist))
;; see of something like \usepackage{natbib} exists.
(save-excursion
(goto-char (point-min))
(re-search-forward "{natbib}" nil t))))
(setq biblatex-used
(or
(member "biblatex" (mapcar (lambda (x) (when (listp x) (nth 1 x))) org-latex-default-packages-alist))
(member "biblatex" (mapcar (lambda (x) (when (listp x) (nth 1 x))) org-latex-packages-alist))
;; see of something like \usepackage{biblatex} exists.
(save-excursion
(goto-char (point-min))
(re-search-forward "{biblatex}" nil t))))
(setq cleveref-used
(or
(member "cleveref" (mapcar (lambda (x) (when (listp x) (nth 1 x))) org-latex-default-packages-alist))
(member "cleveref" (mapcar (lambda (x) (when (listp x) (nth 1 x))) org-latex-packages-alist))
;; see of something like \usepackage{cleveref} exists.
(save-excursion
(goto-char (point-min))
(re-search-forward "{cleveref}" nil t))))
;; setup bib-candidates. This checks a variety of things in the
;; bibliography, bibtex files. check for which bibliographies are used
(cl-pushnew
(cons (format "Using these bibtex files: %s"
(org-ref-find-bibliography))
(lambda () nil))
bib-candidates)
;; Check bibliography style exists
(save-excursion
(goto-char 0)
(unless (re-search-forward "bibliographystyle:\\|\\\\bibliographystyle{" nil t)
(cl-pushnew
(cons "No bibliographystyle found."
(lambda ()
(switch-to-buffer "*org-ref*")
(erase-buffer)
(insert "No bibliography style found. This may be ok, if your latex class style sets that up, but if not this is an error. Try adding something like:
bibliographystyle:unsrt
at the end of you file.
")
(org-mode)))
bib-candidates)))
;; Check if latex knows of the bibliographystyle. We only check links here.
;; I also assume this style exists as a bst file that kpsewhich can find.
(save-excursion
(goto-char 0)
(when (re-search-forward "bibliographystyle:" nil t)
;; on a link. get style
(let ((path (org-element-property :path (org-element-context))))
(unless (= 0 (shell-command (format "kpsewhich %s.bst" path)))
(cl-pushnew
(cons (format "bibliographystyle \"%s\" may be unknown" path)
(lambda ()
(goto-char 0)
(re-search-forward "bibliographystyle:")))
bib-candidates)))))
;; check for multiple bibliography links
(let* ((bib-links (-filter
(lambda (el)
(string= (org-element-property :type el) "bibliography"))
(org-element-map (org-element-parse-buffer) 'link 'identity)))
(n-bib-links (length bib-links)))
(when (> n-bib-links 1)
(mapc (lambda (link)
(setq
bib-candidates
(append
bib-candidates
(list (cons (format "Multiple bibliography link: %s"
(org-element-property :raw-link link))
`(lambda ()
(goto-char ,(org-element-property :begin link))))))))
bib-links)))
;; Check for bibliography files existence.
(mapc (lambda (bibfile)
(unless (file-exists-p bibfile)
(cl-pushnew
(cons
(format "%s does not exist." bibfile)
(lambda ()
(message "Non-existent bibfile.")))
bib-candidates)))
(org-ref-find-bibliography))
;; check for spaces in bibliography
(let ((bibfiles (mapcar 'expand-file-name
(org-ref-find-bibliography))))
(mapc (lambda (bibfile)
(when (string-match " " bibfile)
(cl-pushnew
(cons (format "One or more spaces found in path to %s" bibfile)
(lambda ()
(message "No spaces are allowed in bibtex file paths. We recommend replacing them with -. Underscores usually cause other problems if you don't know what you are doing.")))
bib-candidates)))
bibfiles))
;; validate bibtex files
(let ((bibfiles (mapcar 'expand-file-name
(org-ref-find-bibliography))))
(mapc
(lambda (bibfile)
(unless (with-current-buffer
(find-file-noselect bibfile)
(bibtex-validate))
(cl-pushnew
(cons
(format "Invalid bibtex file found. %S" bibfile)
`(lambda ()
(find-file ,bibfile)))
bib-candidates)))
bibfiles))
;; unreferenced labels
(save-excursion
(save-restriction
(widen)
(goto-char (point-min))
(let ((matches '()))
;; these are the org-ref label:stuff kinds
(while (re-search-forward
"[^#+]label:\\([a-zA-Z0-9:-]*\\)" nil t)
(cl-pushnew (cons
(match-string-no-properties 1)
(point))
matches))
;; now add all the other kinds of labels.
;; #+label:
(save-excursion
(goto-char (point-min))
(while (re-search-forward "^#\\+label:\\s-+\\(.*\\)\\b" nil t)
;; do not do this for tables. We get those in `org-ref-get-tblnames'.
;; who would have thought you have save match data here? Trust me. When
;; I wrote this, you did.
(unless (save-match-data (equal (car (org-element-at-point)) 'table))
(cl-pushnew (cons (match-string-no-properties 1) (point)) matches))))
;; \label{}
(save-excursion
(goto-char (point-min))
(while (re-search-forward "\\\\label{\\([a-zA-Z0-9:-]*\\)}"
nil t)
(cl-pushnew (cons (match-string-no-properties 1) (point)) matches)))
;; #+tblname: and actually #+label
(cl-loop for cell in (org-element-map (org-element-parse-buffer 'element) 'table
(lambda (table)
(cons (org-element-property :name table)
(org-element-property :begin table))))
do
(cl-pushnew cell matches))
;; CUSTOM_IDs
(org-map-entries
(lambda ()
(let ((custom_id (org-entry-get (point) "CUSTOM_ID")))
(when (not (null custom_id))
(cl-pushnew (cons custom_id (point)) matches)))))
(goto-char (point-min))
(while (re-search-forward "^#\\+name:\\s-+\\(.*\\)" nil t)
(cl-pushnew (cons (match-string 1) (point)) matches))
;; unreference labels
(let ((refs (org-element-map (org-element-parse-buffer) 'link
(lambda (el)
(when (or (string= "ref" (org-element-property :type el))
(string= "eqref" (org-element-property :type el))
(string= "pageref" (org-element-property :type el))
(string= "nameref" (org-element-property :type el))
(string= "autoref" (org-element-property :type el))
(string= "cref" (org-element-property :type el))
(string= "Cref" (org-element-property :type el)))
(org-element-property :path el))))))
(cl-loop for (label . p) in matches
do
(when (and label (not (-contains? refs label)))
(cl-pushnew
(cons label (set-marker (make-marker) p))
unreferenced-labels)))))))
(helm :sources `(((name . "Bad citations")
(candidates . ,bad-citations)
(action . (lambda (marker)
(switch-to-buffer (marker-buffer marker))
(goto-char marker)
(org-show-entry))))
((name . "Multiply defined labels")
(candidates . ,bad-labels)
(action . (lambda (marker)
(switch-to-buffer (marker-buffer marker))
(goto-char marker)
(org-show-entry))))
((name . "Bad ref links")
(candidates . ,bad-refs)
(action . (lambda (marker)
(switch-to-buffer (marker-buffer marker))
(goto-char marker)
(org-show-entry))))
((name . "Bad file links")
(candidates . ,bad-files)
(lambda (marker)
(switch-to-buffer (marker-buffer marker))
(goto-char marker)
(org-show-entry)))
((name . "Labels with no ref links")
(candidates . ,unreferenced-labels)
(action . (lambda (marker)
(switch-to-buffer (marker-buffer marker))
(goto-char marker)
(org-show-entry))))
((name . "Bibliography")
(candidates . ,bib-candidates)
(action . (lambda (x)
(switch-to-buffer ,cb)
(funcall x))))
((name . "Miscellaneous")
(candidates . (,(format "org-latex-prefer-user-labels = %s"
org-latex-prefer-user-labels)
,(format "bibtex-dialect = %s" bibtex-dialect)
,(format "biblatex is%srequired." (if biblatex-required " " " not "))
,(format "biblatex is%sused." (if biblatex-used " " " not "))
,(format "org-version = %s" (org-version))
,(format "completion backend = %s" org-ref-completion-library)
,(format "org-latex-pdf-process is defined as %s" org-latex-pdf-process)
,(format "natbib is%srequired." (if natbib-required " " " not "))
,(format "natbib is%sused." (if natbib-used " " " not "))
,(format "cleveref is%srequired." (if cleveref-required " " " not "))
,(format "cleveref is%sused." (if cleveref-used " " " not "))))
(action . nil))
((name . "Utilities")
(candidates . (("Check buffer again" . org-ref)
("Insert citation" . helm-bibtex)
("Insert label link" . org-ref-helm-insert-label-link)
("Insert ref link" . org-ref-helm-insert-ref-link)
("List of figures" . org-ref-list-of-figures)
("List of tables" . org-ref-list-of-tables)
("Table of contents" . helm-org-in-buffer-headings)))
(action . (lambda (x)
(switch-to-buffer ,cb)
(funcall x))))
((name . "Document utilities")
(candidates . (("Spell check document" . ispell)))
(action . (lambda (x)
(switch-to-buffer ,cb)
(funcall x))))
;; Exports
((name . "Export functions")
(candidates . (("Extract cited entries" . org-ref-extract-bibtex-entries)
("Export to html and open" . (lambda ()
(org-open-file
(org-html-export-to-html))))
("Export to pdf and open" . (lambda ()
(org-open-file
(org-latex-export-to-pdf))))
("Export to manuscript pdf and open" . ox-manuscript-export-and-build-and-open)
("Export submission manuscript pdf and open" . ox-manuscript-build-submission-manuscript-and-open)))
(action . (lambda (x)
(switch-to-buffer ,cb)
(funcall x))))))))
;;;###autoload
(defun helm-tag-bibtex-entry ()
"Helm interface to add keywords to a bibtex entry.
Run this with the point in a bibtex entry."
(interactive)
(let ((keyword-source `((name . "Existing keywords")
(candidates . ,(org-ref-bibtex-keywords))
(action . (lambda (candidate)
(org-ref-set-bibtex-keywords
(mapconcat
'identity
(helm-marked-candidates)
", "))))))
(fallback-source (helm-build-dummy-source "Add new keywords"
:action (lambda (candidate)
(org-ref-set-bibtex-keywords helm-pattern)))))
(helm :sources `(,keyword-source ,fallback-source))))
(provide 'org-ref-helm)
;;; org-ref-helm.el ends here

View File

@@ -189,8 +189,7 @@ in the file. Data comes from worldcat."
(org-ref-isbn-clean-bibtex-entry)
(org-ref-clean-bibtex-entry)
(bibtex-fill-entry)
(s-trim (buffer-string))
(buffer-string)))
(s-trim (buffer-string))))
(save-buffer))))
(provide 'org-ref-isbn)

View File

@@ -1,561 +0,0 @@
;;; org-ref-ivy-cite.el --- Use ivy for completion in org-ref -*- lexical-binding: t; -*-
;; Copyright (C) 2016 John Kitchin
;; Author: John Kitchin <jkitchin@andrew.cmu.edu>
;; Keywords:
;; 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 <http://www.gnu.org/licenses/>.
;;; Commentary:
;;
(declare-function 'org-ref-insert-key-at-point "org-ref-core.el")
(declare-function 'org-ref-find-bibliography "org-ref-core.el")
(declare-function 'org-ref-get-labels "org-ref-core.el")
(declare-function 'org-ref-get-bibtex-key-and-file "org-ref-core.el")
;;; Code:
(require 'ivy)
(require 'org-ref-bibtex)
(require 'org-ref-citeproc)
(require 'bibtex-completion)
;; This lets you customize how the completion for ivy is displayed. The default
;; is in the minibuffer. You may like to see something more like a popup though.
(defcustom org-ref-ivy-display-function nil
"ivy function to display completion with.
Set to `ivy-display-function-overlay' to get popups at point."
:type 'function
:group 'org-ref)
(when org-ref-ivy-display-function
(add-to-list 'ivy-display-functions-alist
`(org-ref-ivy-insert-cite-link . ,org-ref-ivy-display-function))
(add-to-list 'ivy-display-functions-alist
`(org-ref-ivy-insert-label-link . ,org-ref-ivy-display-function))
(add-to-list 'ivy-display-functions-alist
`(org-ref-ivy-insert-ref-link . ,org-ref-ivy-display-function)))
(defvar org-ref-cite-types)
(defvar org-ref-show-citation-on-enter)
(defvar org-ref-ivy-cite-marked-candidates '()
"Holds entries marked in `org-ref-ivy-insert-cite-link'.")
;;;###autoload
(defun org-ref-ivy-cite-completion ()
"Use ivy for completion."
(interactive)
;; Define core functions for org-ref
(setq org-ref-insert-link-function 'org-ref-insert-link
org-ref-insert-cite-function 'org-ref-ivy-insert-cite-link
org-ref-insert-label-function 'org-ref-ivy-insert-label-link
org-ref-insert-ref-function 'org-ref-ivy-insert-ref-link
org-ref-cite-onclick-function (lambda (_) (org-ref-cite-hydra/body))))
(org-ref-ivy-cite-completion)
(define-key org-mode-map
(kbd org-ref-insert-cite-key)
org-ref-insert-link-function)
(defun or-looking-forward-cite ()
"Return if point is in the position before a citation."
(save-excursion
(forward-char)
(-contains? org-ref-cite-types
(org-element-property
:type
(org-element-context)))))
(defun or-looking-back-cite ()
"Return if point is in the position after a citation."
(save-excursion
(forward-char -1)
(-contains? org-ref-cite-types
(org-element-property
:type
(org-element-context)))))
(defun or-ivy-bibtex-insert-cite (entry)
"Insert a citation for ENTRY.
If `org-ref-ivy-cite-marked-candidates' is non-nil then they are added instead of ENTRY.
ENTRY is selected from `orhc-bibtex-candidates'."
(with-ivy-window
(if org-ref-ivy-cite-marked-candidates
(cl-loop for entry in org-ref-ivy-cite-marked-candidates
do
(if ivy-current-prefix-arg
(let ((org-ref-default-citation-link (ivy-read "Type: " org-ref-cite-types)))
(org-ref-insert-key-at-point (list (cdr (assoc "=key=" entry)))))
(org-ref-insert-key-at-point (list (cdr (assoc "=key=" entry))))))
(if ivy-current-prefix-arg
(let ((org-ref-default-citation-link (ivy-read "Type: " org-ref-cite-types)))
(org-ref-insert-key-at-point (list (cdr (assoc "=key=" entry)))))
(org-ref-insert-key-at-point (list (cdr (assoc "=key=" entry))))))))
(defun or-ivy-bibtex-open-pdf (entry)
"Open the pdf associated with ENTRY.
ENTRY is selected from `orhc-bibtex-candidates'."
(with-ivy-window
(let ((pdf (expand-file-name
(format "%s.pdf"
(cdr (assoc "=key=" entry)))
org-ref-pdf-directory)))
(if (file-exists-p pdf)
(org-open-file pdf)
(message "No pdf found for %s" (cdr (assoc "=key=" entry)))))))
(defun or-ivy-bibtex-open-notes (entry)
"Open the notes associated with ENTRY.
ENTRY is selected from `orhc-bibtex-candidates'."
(with-ivy-window
(org-ref-open-notes-at-point
(cdr (assoc "=key=" entry)))))
(defun or-ivy-bibtex-open-entry (entry)
"Open the bibtex file at ENTRY.
ENTRY is selected from `orhc-bibtex-candidates'."
(find-file (cdr (assoc "bibfile" entry)))
(goto-char (cdr (assoc "position" entry)))
(bibtex-beginning-of-entry))
(defun or-ivy-bibtex-copy-entry (entry)
"Copy selected bibtex ENTRY to the clipboard."
(with-temp-buffer
(save-window-excursion
(or-ivy-bibtex-open-entry entry)
(bibtex-copy-entry-as-kill))
(bibtex-yank)
(kill-region (point-min) (point-max))))
(defun or-ivy-bibtex-open-url (entry)
"Open the URL associated with ENTRY.
ENTRY is selected from `orhc-bibtex-candidates'."
(let ((url (cdr (assoc "url" entry))))
(if url
(browse-url url)
(message "No url found for %s" (cdr (assoc "=key=" entry))))))
(defun or-ivy-bibtex-open-doi (entry)
"Open the DOI associated with ENTRY.
ENTRY is selected from `orhc-bibtex-candidates'."
(let ((doi (cdr (assoc "doi" entry))))
(if doi
(browse-url (format "http://dx.doi.org/%s" doi))
(message "No doi found for %s" (cdr (assoc "=key=" entry))))))
(defun or-ivy-bibtex-set-keywords (entry)
"Prompt for keywords, and put them on the selected ENTRY."
(let ((keywords (read-string "Keyword(s) comma-separated: " ))
entry-keywords)
(save-window-excursion
(or-ivy-bibtex-open-entry entry)
(setq entry-keywords (bibtex-autokey-get-field "keywords"))
(bibtex-set-field
"keywords"
(if (> (length entry-keywords) 0)
(concat entry-keywords ", " keywords)
keywords)))))
(defun or-ivy-bibtex-email-entry (entry)
"Insert selected ENTRY and attach pdf file to an email.
Create email unless called from an email."
(with-ivy-window
(let ((goto-to nil))
(unless (memq major-mode '(message-mode mu4e-compose-mode))
(setq goto-to t)
(compose-mail)
(message-goto-body))
(save-window-excursion
(or-ivy-bibtex-open-entry entry)
(bibtex-copy-entry-as-kill))
(insert (pop bibtex-entry-kill-ring))
(insert "\n")
(let ((pdf (expand-file-name
(format "%s.pdf"
(cdr (assoc "=key=" entry)))
org-ref-pdf-directory)))
(if (file-exists-p pdf)
(mml-attach-file pdf)))
(when goto-to
(message-goto-to)))))
(defun or-ivy-bibtex-formatted-citation (entry)
"Return string containing formatted citations for ENTRY.
This uses a citeproc library."
(let ((enable-recursive-minibuffers t))
(ivy-read "Style: " '("unsrt" "author-year")
:action 'load-library
:require-match t
:preselect "unsrt"
:caller 'or-ivy-formatted-citation)
(format "%s\n\n" (orhc-formatted-citation entry))))
(defun or-ivy-bibtex-insert-formatted-citation (entry)
"Insert formatted citations at point for selected entries."
(with-ivy-window
(insert (mapconcat
'identity
(cl-loop for entry in (or org-ref-ivy-cite-marked-candidates (list entry))
collect (org-ref-format-bibtex-entry entry))
"\n\n"))))
(defun or-ivy-bibtex-copy-formatted-citation (entry)
"Copy formatted citation to clipboard for ENTRY."
(kill-new (org-ref-format-entry (cdr (assoc "=key=" entry)))))
(defun or-ivy-bibtex-add-entry (_)
"Open a bibliography file and move point to the end, in order
to add a new bibtex entry. The arg is selected from
`orhc-bibtex-candidates' but ignored."
(ivy-read "bibtex file: " org-ref-bibtex-files
:require-match t
:action 'find-file
:caller 'or-ivy-bibtex-add-entry)
(widen)
(goto-char (point-max))
(unless (bolp)
(insert "\n")))
(defvar org-ref-ivy-cite-actions
'(("b" or-ivy-bibtex-open-entry "Open bibtex entry")
("B" or-ivy-bibtex-copy-entry "Copy bibtex entry")
("p" or-ivy-bibtex-open-pdf "Open pdf")
("n" or-ivy-bibtex-open-notes "Open notes")
("u" or-ivy-bibtex-open-url "Open url")
("d" or-ivy-bibtex-open-doi "Open doi")
("k" or-ivy-bibtex-set-keywords "Add keywords")
("e" or-ivy-bibtex-email-entry "Email entry")
("f" or-ivy-bibtex-insert-formatted-citation "Insert formatted citation")
("F" or-ivy-bibtex-copy-formatted-citation "Copy formatted citation")
("a" or-ivy-bibtex-add-entry "Add bibtex entry"))
"List of additional actions for `org-ref-ivy-insert-cite-link' (the default action being to insert a citation).")
(defvar org-ref-ivy-cite-re-builder 'ivy--regex-ignore-order
"Regex builder to use in `org-ref-ivy-insert-cite-link'. Can be set to nil to use Ivy's default).")
(defun org-ref-swap (i j lst)
"Swap index I and J in the list LST."
(let ((tempi (nth i lst)))
(setf (nth i lst) (nth j lst))
(setf (nth j lst) tempi))
lst)
(defun org-ref-ivy-current ()
(if (boundp 'ivy--current)
ivy--current
(ivy-state-current ivy-last)))
(defun org-ref-ivy-move-up ()
"Move ivy candidate up and update candidates."
(interactive)
(setf (ivy-state-collection ivy-last)
(org-ref-swap ivy--index (1- ivy--index) (ivy-state-collection ivy-last)))
(setf (ivy-state-preselect ivy-last) (org-ref-ivy-current))
(ivy--reset-state ivy-last))
(defun org-ref-ivy-move-down ()
"Move ivy candidate down."
(interactive)
(setf (ivy-state-collection ivy-last)
(org-ref-swap ivy--index (1+ ivy--index) (ivy-state-collection ivy-last)))
(setf (ivy-state-preselect ivy-last) (org-ref-ivy-current))
(ivy--reset-state ivy-last))
(defun org-ref-ivy-sort-year-ascending ()
"Sort entries by year in ascending order."
(interactive)
(setf (ivy-state-collection ivy-last)
(cl-sort (copy-sequence (ivy-state-collection ivy-last))
(lambda (a b)
(let ((y1 (string-to-number (or (cdr (assoc "year" a)) "0")))
(y2 (string-to-number (or (cdr (assoc "year" b)) "0"))))
(< y1 y2)))))
(setf (ivy-state-preselect ivy-last) (org-ref-ivy-current))
(ivy--reset-state ivy-last))
(defun org-ref-ivy-sort-year-descending ()
"sort entries by year in descending order."
(interactive)
(setf (ivy-state-collection ivy-last)
(cl-sort (copy-sequence (ivy-state-collection ivy-last))
(lambda (a b)
(let ((y1 (string-to-number (or (cdr (assoc "year" a)) "0")))
(y2 (string-to-number (or (cdr (assoc "year" b)) "0"))))
(> y1 y2)))))
(setf (ivy-state-preselect ivy-last) (org-ref-ivy-current))
(ivy--reset-state ivy-last))
;; * marking candidates
(defun org-ref-ivy-mark-candidate ()
"Add current candidate to `org-ref-ivy-cite-marked-candidates'.
If candidate is already in, remove it."
(interactive)
(let ((cand (or (assoc (org-ref-ivy-current) (ivy-state-collection ivy-last))
(org-ref-ivy-current))))
(if (-contains? org-ref-ivy-cite-marked-candidates cand)
;; remove it from the marked list
(setq org-ref-ivy-cite-marked-candidates
(-remove-item cand org-ref-ivy-cite-marked-candidates))
;; add to list
(setq org-ref-ivy-cite-marked-candidates
(append org-ref-ivy-cite-marked-candidates (list cand)))))
(ivy-next-line))
(defun org-ref-ivy-show-marked-candidates ()
"Show marked candidates."
(interactive)
(setf (ivy-state-collection ivy-last) org-ref-ivy-cite-marked-candidates)
(setf (ivy-state-preselect ivy-last) (org-ref-ivy-current))
(ivy--reset-state ivy-last))
(defun org-ref-ivy-show-all ()
"Show all the candidates."
(interactive)
(setf (ivy-state-collection ivy-last)
(orhc-bibtex-candidates))
(ivy--reset-state ivy-last))
;; * org-ref-cite keymap
(defvar org-ref-ivy-cite-keymap
(let ((map (make-sparse-keymap)))
(define-key map (kbd "C-<SPC>") 'org-ref-ivy-mark-candidate)
(define-key map (kbd "C-,") 'org-ref-ivy-show-marked-candidates)
(define-key map (kbd "C-.") 'org-ref-ivy-show-all)
(define-key map (kbd "C-<up>") 'org-ref-ivy-move-up)
(define-key map (kbd "C-<down>") 'org-ref-ivy-move-down)
(define-key map (kbd "C-y") 'org-ref-ivy-sort-year-ascending)
(define-key map (kbd "C-M-y") 'org-ref-ivy-sort-year-descending)
(define-key map (kbd "C-k") (lambda ()
(interactive)
(beginning-of-line)
(kill-visual-line)
(setf (ivy-state-collection ivy-last)
(orhc-bibtex-candidates))
(setf (ivy-state-preselect ivy-last) (org-ref-ivy-current))
(ivy--reset-state ivy-last)))
(define-key map (kbd "C-<return>")
(lambda ()
"Apply action and move to next/previous candidate."
(interactive)
(ivy-call)
(ivy-next-line)))
;; (define-key ivy-minibuffer-map (kbd "M-<return>")
;; (lambda ()
;; "Apply default action to all marked candidates."
;; (interactive)
;; (mapc (ivy--get-action ivy-last)
;; org-ref-ivy-cite-marked-candidates)
;; (ivy-exit-with-action (function (lambda (_) nil)))))
map)
"A key map for `org-ref-ivy-insert-cite-link'.")
(ivy-set-actions
'org-ref-ivy-insert-cite-link
org-ref-ivy-cite-actions)
(defun org-ref-ivy-insert-cite-link (&optional arg)
"ivy function for interacting with bibtex.
Uses `org-ref-find-bibliography' for bibtex sources, unless a
prefix ARG is used, which uses `org-ref-default-bibliography'."
(interactive "P")
(setq org-ref-bibtex-files (if arg
org-ref-default-bibliography
(org-ref-find-bibliography)))
(setq org-ref-ivy-cite-marked-candidates '())
(ivy-read "Open: " (orhc-bibtex-candidates)
:require-match t
:keymap org-ref-ivy-cite-keymap
:re-builder org-ref-ivy-cite-re-builder
:action 'or-ivy-bibtex-insert-cite
:caller 'org-ref-ivy-insert-cite-link))
(defun org-ref-ivy-cite-transformer (s)
"Make entry red if it is marked."
(let* ((fill-column (frame-width))
(fill-prefix " ")
(wrapped-s (with-temp-buffer
(insert s)
(fill-paragraph)
(buffer-string))))
(if (-contains?
(if (listp (car org-ref-ivy-cite-marked-candidates))
(mapcar 'car org-ref-ivy-cite-marked-candidates)
org-ref-ivy-cite-marked-candidates)
s)
(propertize wrapped-s 'face 'font-lock-warning-face)
(propertize wrapped-s 'face nil))))
(ivy-set-display-transformer
'org-ref-ivy-insert-cite-link
'org-ref-ivy-cite-transformer )
(defun org-ref-ivy-insert-label-link ()
"Insert a label with ivy."
(interactive)
(insert
(concat (if (not (looking-back "label:" 6)) "label:" "")
(ivy-read "label: " (org-ref-get-labels)
:caller 'org-ref-ivy-insert-label-link))))
(defun org-ref-ivy-insert-ref-link ()
"Insert a ref link with ivy.
Use a prefix arg to select the ref type."
(interactive)
(let ((label (ivy-read "label: " (org-ref-get-labels) :require-match t
:caller 'org-ref-ivy-insert-ref-link)))
(cond
;; from a colon insert
((looking-back ":" 1)
(insert label))
;; non-default
(ivy-current-prefix-arg
(insert
(ivy-read "type: " org-ref-ref-types)
":"
label))
;; default
(t
(insert
(or (when (looking-at "$") " ") "")
(concat (org-ref-infer-ref-type label)
":"
label))))))
(require 'hydra)
(setq hydra-is-helpful t)
(defhydra org-ref-cite-hydra (:color blue)
"
_p_: Open pdf _w_: WOS _g_: Google Scholar _K_: Copy citation to clipboard
_u_: Open url _r_: WOS related _P_: Pubmed _k_: Copy key to clipboard
_n_: Open notes _c_: WOS citing _C_: Crossref _f_: Copy formatted entry
_o_: Open entry _e_: Email entry ^ ^ _q_: quit
_i_: Insert cite _h_: change type
"
("o" org-ref-open-citation-at-point nil)
("p" (funcall org-ref-open-pdf-function) nil)
("n" org-ref-open-notes-at-point nil)
("u" org-ref-open-url-at-point nil)
("w" org-ref-wos-at-point nil)
("r" org-ref-wos-related-at-point nil)
("c" org-ref-wos-citing-at-point nil)
("g" org-ref-google-scholar-at-point nil)
("P" org-ref-pubmed-at-point nil)
("C" org-ref-crossref-at-point nil)
("K" org-ref-copy-entry-as-summary nil)
("k" (progn
(kill-new
(car (org-ref-get-bibtex-key-and-file))))
nil)
("f" (kill-new
(org-ref-format-entry (org-ref-get-bibtex-key-under-cursor)))
nil)
("e" (kill-new (save-excursion
(org-ref-open-citation-at-point)
(org-ref-email-bibtex-entry)))
nil)
("i" (funcall org-ref-insert-cite-function))
("h" org-ref-change-cite-type)
("q" nil))
(defun org-ref-ivy-onclick-actions ()
"An alternate click function that uses ivy for action selection.
Each action is taken from `org-ref-ivy-cite-actions'. Each action
should act on a bibtex entry that matches the key in
`orhc-bibtex-candidates'. Set `org-ref-cite-onclick-function' to
this function to use it."
(interactive)
(ivy-read
"action: "
(cl-loop for i from 0
for (_ func s) in
org-ref-ivy-cite-actions
collect (cons (format "%2s. %s" i s) func))
:action (lambda (f)
(let* ((key (car (org-ref-get-bibtex-key-and-file)))
(entry (cdr (elt (orhc-bibtex-candidates)
(-elem-index
key
(cl-loop for entry in (orhc-bibtex-candidates)
collect (cdr (assoc "=key=" entry ))))))))
(funcall f entry)))))
;; * org-ref-ivy-set-keywords
(defvar org-ref-ivy-set-keywords-keymap
(let ((map (make-sparse-keymap)))
(define-key map (kbd "C-<SPC>") 'org-ref-ivy-mark-candidate)
(define-key map (kbd "C-,") 'org-ref-ivy-show-marked-candidates)
(define-key map (kbd "C-.") 'org-ref-ivy-show-all)
(define-key map (kbd "C-<up>") 'org-ref-ivy-move-up)
(define-key map (kbd "C-<down>") 'org-ref-ivy-move-down)
map)
"A key map for `org-ref-ivy-set-keywords'.")
(defun org-ref-ivy-set-keywords ()
"Add keywords to bibtex entries selected by org-ref-ivy."
(interactive)
(setq org-ref-ivy-cite-marked-candidates '())
(ivy-read "Keywords: " (org-ref-bibtex-keywords)
:keymap org-ref-ivy-set-keywords-keymap
:caller 'org-ref-ivy-set-keywords
:action (lambda (key)
(org-ref-set-bibtex-keywords
(mapconcat
'identity
(or org-ref-ivy-cite-marked-candidates (list key))
", ")))))
(ivy-set-display-transformer
'org-ref-ivy-set-keywords
'org-ref-ivy-cite-transformer)
(provide 'org-ref-ivy-cite)
;;; org-ref-ivy-cite.el ends here

View File

@@ -1,12 +1,12 @@
;;; org-ref-ivy.el --- org-ref with ivy completion -*- lexical-binding: t; -*-
;; Copyright (C) 2016 John Kitchin
;; Copyright (C) 2016-2021 John Kitchin
;; Author: John Kitchin <jkitchin@andrew.cmu.edu>
;; URL: https://github.com/jkitchin/org-ref
;; Version: 0.8.1
;; Version: 1.0
;; Keywords: org-mode, cite, ref, label
;; Package-Requires: ((dash "2.11.0") (ivy "0.8.0") (hydra "0.13.2") (key-chord "0") (s "1.10.0") (f "0.18.0") (parsebib "0") (emacs "24.4"))
;; Package-Requires: ((org-ref "0") (ivy-bibtex "0"))
;; This file is not currently part of GNU Emacs.
@@ -24,11 +24,126 @@
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
(setq org-ref-completion-library 'org-ref-ivy-cite)
;;
;; This customizes org-ref specifically around using ivy and ivy-bibtex. The
;; citation selection looks like `ivy-bibtex' but it is a customized ivy
;; function with customized actions.
(require 'org-ref-ivy-cite)
(require 'org-ref-core)
(require 'ivy-bibtex)
;; all these functions are defined in ivy-bibtex, but not in a variable. Here
;; you can set them as you see fit.
(defcustom org-ref-citation-alternate-insert-actions
'(("p" ivy-bibtex-open-pdf "Open PDF file (if present)")
("u" ivy-bibtex-open-url-or-doi "Open URL or DOI in browser")
;; this insert-citation only inserts an org-ref cite.
;; ("c" ivy-bibtex-insert-citation "Insert citation")
("R" ivy-bibtex-insert-reference "Insert formatted reference")
("k" ivy-bibtex-insert-key "Insert BibTeX key")
("b" ivy-bibtex-insert-bibtex "Insert BibTeX entry")
("a" ivy-bibtex-add-PDF-attachment "Attach PDF to email")
("e" ivy-bibtex-edit-notes "Edit notes")
("s" ivy-bibtex-show-entry "Show entry")
("l" ivy-bibtex-add-pdf-to-library "Add PDF to library")
("h" (lambda (candidate)
(org-insert-heading)
(insert (bibtex-completion-apa-format-reference
(cdr (assoc "=key=" candidate)))
" "
(format "cite:&%s" (cdr (assoc "=key=" candidate)))))
"Insert org-heading")
("m" (lambda (candidate)
(insert (bibtex-completion-apa-format-reference
(cdr (assoc "=key=" candidate)))))
"Insert formatted citation")
("f" (lambda (_candidate) (ivy-bibtex-fallback ivy-text)) "Fallback options"))
"Alternate actions to do instead of inserting."
:type '(list (repeat (string function string)))
:group 'org-ref)
;; This is modified from ivy-bibtex which had " " instead of "" which breaks marking.
(defun org-ref-ivy-bibtex-display-transformer (candidate)
"Prepare bib entry CANDIDATE for display."
(let* ((width (- (frame-width) 2))
(idx (get-text-property 1 'idx candidate))
(entry (cdr (nth idx (ivy-state-collection ivy-last)))))
(s-concat (if (s-starts-with-p ivy-mark-prefix candidate) ivy-mark-prefix "")
(bibtex-completion-format-entry entry width))))
(ivy-configure 'org-ref-cite-insert-ivy :display-transformer-fn 'org-ref-ivy-bibtex-display-transformer)
(defun org-ref-cite-multi-insert-ivy (candidates)
"A multi-action function to insert CANDIDATES."
(with-ivy-window
(org-ref-insert-cite-keys
(mapcar (lambda (entry)
(cdr (assoc "=key=" (cdr entry))))
candidates)
ivy-current-prefix-arg)))
(defun org-ref-cite-insert-ivy ()
"Function for inserting a citation."
(interactive)
;; Set this in the function so it is updated if you change the functions while
;; writing
(ivy-set-actions
'org-ref-cite-insert-ivy
org-ref-citation-alternate-insert-actions)
;; This initializes bibtex if the variable is not defined.
(unless bibtex-completion-display-formats-internal
(bibtex-completion-init))
(let* ((bibtex-completion-bibliography (org-ref-find-bibliography))
(candidates (bibtex-completion-candidates)))
(ivy-read "org-ref-ivy BibTeX entries: " candidates
:preselect (ivy-thing-at-point)
:multi-action #'org-ref-cite-multi-insert-ivy
:action '(1
("o" (lambda (candidate)
(org-ref-insert-cite-key
(cdr (assoc "=key=" (cdr candidate)))
ivy-current-prefix-arg))
"insert")
("r" (lambda (candidate)
(let* ((object (org-element-context))
(type (org-element-property :type object))
(begin (org-element-property :begin object))
(end (org-element-property :end object))
(link-string (org-element-property :path object))
(data (org-ref-parse-cite-path link-string))
(references (plist-get data :references))
(cp (point))
(key)
keys i)
;; We only want this to work on citation links
(when (assoc type org-ref-cite-types)
(setq key (org-ref-get-bibtex-key-under-cursor))
(if (null key)
;; delete the whole cite
(cl--set-buffer-substring begin end "")
(setq i (seq-position
references key
(lambda (el key)
(string= key
(plist-get el :key)))))
(setf (plist-get (nth i references) :key)
(cdr (assoc "=key=" (cdr candidate))))
(setq data (plist-put data :references references))
(save-excursion
(goto-char begin)
(re-search-forward link-string)
(replace-match (org-ref-interpret-cite-data data)))
(goto-char cp)))))
"Replace key at point"))
:caller 'org-ref-cite-insert-ivy)))
(org-ref-ivy-cite-completion)
(provide 'org-ref-ivy)

View File

@@ -0,0 +1,60 @@
;;; org-ref-label-link.el --- -*- lexical-binding: t; -*-
;;
;; Copyright (C) 2021 John Kitchin
;; Author: John Kitchin <jkitchin@andrew.cmu.edu>
;; Keywords: convenience
;; 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 <http://www.gnu.org/licenses/>.
;;
;;; Commentary:
;;
;;; Code:
(defface org-ref-label-face
`((t (:inherit org-link :foreground "dark magenta")))
"Color for ref links in `org-ref'."
:group 'org-ref-faces)
;;** label link (maybe deprecated)
(org-link-set-parameters
"label"
:export (lambda (path _desc format)
(cond
((eq format 'latex)
(format "\\label{%s}" path))))
:face 'org-ref-label-face
:help-echo "A label")
;;;###autoload
(defun org-ref-insert-label-link ()
"Insert a new label with completion.
The completion helps ensure you use a unique label."
(interactive)
(let* ((known-labels (mapcar 'car (org-ref-get-labels)))
(new-label (completing-read "Label: " known-labels nil)))
(when (member new-label known-labels)
(warn "Inserting duplicate label"))
(insert (format "label:%s" new-label))))
(provide 'org-ref-label-link)
;;; org-ref-label-link.el ends here

View File

@@ -1,6 +1,6 @@
;;; org-ref-latex.el --- org-ref functionality for LaTeX files -*- lexical-binding: t; -*-
;; Copyright (C) 2015 John Kitchin
;; Copyright (C) 2015-2021 John Kitchin
;; Author: John Kitchin <jkitchin@andrew.cmu.edu>
;; Keywords: languages
@@ -19,129 +19,83 @@
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary: Make cites in LaTeX documents clickable, and with tooltips.
;; We use font-lock to add some functionality to the
;;
;; We use font-lock to add some functionality to the keys.
;;; Code:
(require 'org-ref-core)
(require 'org-ref-citation-links)
(require 'bibtex-completion)
(defvar latex-mode-map)
(defvar org-ref-cite-types)
(defvar org-ref-latex-cite-re
(concat "\\\\\\(" (mapconcat
(lambda (x)
(replace-regexp-in-string "\\*" "\\\\*" x))
org-ref-cite-types
"\\|")
(concat "\\\\\\(?1:" (mapconcat
(lambda (x)
(replace-regexp-in-string "\\*" "\\\\*" x))
(mapcar 'car org-ref-cite-types)
"\\|")
"\\)"
"\\(\\[[^}]*\\)?" ; optional []
"\\(\\[[^}]*\\)?" ; optional []
"{\\([^}]*\\)}")
"Regexp for LaTeX citations. \citetype[optional]{some,keys}.
"\\(?2:\\[[^]]*\\]\\)?" ; optional []
"\\(?3:\\[[^]]*\\]\\)?" ; optional []
"{\\(?4:[^}]*\\)}") ; group 4 contains the keys
"Regexp for LaTeX citations. \\citetype[opti{o}nal][optiona{l}]{some,keys}.
The clickable part are the keys.")
(defun org-ref-latex-get-key ()
"Figure out what key the cursor is on."
(let (start end)
;; look back for , or {
(save-excursion
(re-search-backward ",\\|{")
(setq start (+ 1 (point))))
;; look forward to , or }
(save-excursion
(re-search-forward ",\\|}")
(setq end (- (point) 1)))
(buffer-substring-no-properties start end)))
;;;###autoload
(defun org-ref-latex-debug ()
(interactive)
(message-box "%S\n%S\n%S\n%S"
(org-ref-latex-get-key)
(org-ref-find-bibliography)
(org-ref-get-bibtex-key-and-file (org-ref-latex-get-key))
(ignore-errors
(org-ref-latex-help-echo nil nil (point)))))
(defun org-ref-latex-jump-to-bibtex (&optional key)
"Jump to the KEY at point."
(let ((results (org-ref-get-bibtex-key-and-file
(or key (org-ref-latex-get-key)))))
(find-file (cdr results))
(bibtex-search-entry (car results))))
;;;###autoload
(defun org-ref-latex-click ()
"Jump to entry clicked on."
(interactive)
(helm :sources '(((name . "Actions")
(candidates . (("Open Bibtex entry" . org-ref-latex-jump-to-bibtex)
("Bibtex entry menu" . (lambda ()
(org-ref-latex-jump-to-bibtex)
(org-ref-bibtex-hydra/body)))))
(action . (lambda (f)
(funcall f)))))))
(defun org-ref-latex-help-echo (_window _object position)
"Get tool tip for a key in WINDOW for OBJECT at POSITION."
(defun org-ref-latex-get-bibliography ()
"Find bibliographies in the tex file"
(save-excursion
(goto-char position)
(let* ((key (org-ref-latex-get-key))
(results (org-ref-get-bibtex-key-and-file key))
(bibfile (cdr results))
citation
tooltip)
(setq citation
(if bibfile
(save-excursion
(with-temp-buffer
(insert-file-contents bibfile)
(bibtex-set-dialect
(parsebib-find-bibtex-dialect) t)
(bibtex-search-entry key)
(org-ref-bib-citation)))
"!!! No entry found !!!"))
(setq tooltip
(with-temp-buffer
(insert citation)
(fill-paragraph)
(buffer-string)))
tooltip)))
(let ((bibliography '()))
(goto-char (point-min))
(while (re-search-forward "\\\\bibliography{\\(?1:.*\\)}" nil t)
(setq bibliography (append bibliography
(mapcar (lambda (f)
(concat f ".bib"))
(split-string (match-string-no-properties 1) ",")))))
(goto-char (point-min))
(while (re-search-forward "\\\\addbibresource{\\(?1:.*\\)}" nil t)
(setq bibliography (append bibliography (list (match-string-no-properties 1)))))
bibliography)))
(defun org-ref-next-latex-cite (&optional limit)
"Font-lock function to make cites in LaTeX documents clickable."
(when (re-search-forward org-ref-latex-cite-re limit t)
(while (re-search-forward org-ref-latex-cite-re limit t)
(setq font-lock-extra-managed-props (delq 'help-echo font-lock-extra-managed-props))
(add-text-properties
(match-beginning 3)
(match-end 3)
`(mouse-face
highlight
local-map ,(let ((map (copy-keymap latex-mode-map)))
(define-key map [mouse-1]
'org-ref-latex-click)
map)
help-echo org-ref-latex-help-echo))))
(goto-char (match-beginning 0))
(let ((end (match-end 0)))
(cl-loop for key in (split-string (match-string-no-properties 4) ",")
do
(save-match-data
(search-forward key)
(add-text-properties
(match-beginning 0)
(match-end 0)
`(mouse-face highlight
local-map ,(let ((map (copy-keymap latex-mode-map)))
(define-key map [mouse-1]
`(lambda ()
(interactive)
(let ((bibtex-completion-bibliography (org-ref-latex-get-bibliography)))
(bibtex-completion-show-entry (list ,key))
(bibtex-beginning-of-entry))))
map)
help-echo ,(let* ((bibtex-completion-bibliography (org-ref-latex-get-bibliography)))
(bibtex-completion-apa-format-reference key))))))
(goto-char end))))
(defun org-ref-latex-cite-on ()
"Add the font-lock on for citations."
(font-lock-add-keywords
nil
'((org-ref-next-latex-cite 3 font-lock-constant-face))))
'latex-mode
'((org-ref-next-latex-cite 0 font-lock-constant-face))))
(add-hook 'latex-mode-hook 'org-ref-latex-cite-on)
(add-hook 'LaTeX-mode-hook 'org-ref-latex-cite-on)
(provide 'org-ref-latex)
;;; org-ref-latex.el ends here

View File

@@ -0,0 +1,304 @@
;;; org-ref-misc-links.el --- Miscellaneous links -*- lexical-binding: t; -*-
;;
;; Copyright (C) 2021 John Kitchin
;; Author: John Kitchin <jkitchin@andrew.cmu.edu>
;; Keywords: convenience
;; 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 <http://www.gnu.org/licenses/>.
;;
;; * Miscellaneous links
;;; Commentary:
;;
;;; Code:
;;** List of figures
;;;###autoload
(defun org-ref-list-of-figures (&optional _arg)
"Generate buffer with list of figures in them.
ARG does nothing.
Ignore figures in COMMENTED sections."
(interactive)
(save-excursion
(widen)
(let* ((c-b (buffer-name))
(counter 0)
(list-of-figures
(org-element-map (org-ref-parse-buffer) 'link
(lambda (link)
"create a link for to the figure"
(when
(and (string= (org-element-property :type link) "file")
(string-match-p
"[^.]*\\.\\(png\\|jpg\\|eps\\|pdf\\|svg\\)$"
(org-element-property :path link))
;; ignore commented sections
(save-excursion
(goto-char (org-element-property :begin link))
(not (or (org-in-commented-heading-p)
(org-at-comment-p)
(-intersection (org-get-tags) org-export-exclude-tags)))))
(cl-incf counter)
(let* ((start (org-element-property :begin link))
(linenum (progn (goto-char start) (line-number-at-pos)))
(fname (org-element-property :path link))
(parent (car (cdr
(org-element-property :parent link))))
(caption (cl-caaar (plist-get parent :caption)))
(name (plist-get parent :name)))
(if caption
(format "[[file:%s::%s][Figure %s:]] %s\n" c-b linenum counter caption)
;; if it has no caption, try the name
;; if it has no name, use the file name
(cond (name
(format "[[file:%s::%s][Figure %s:]] %s\n" c-b linenum counter name))
(fname
(format "[[file:%s::%s][Figure %s:]] %s\n"
c-b linenum counter fname))))))))))
(switch-to-buffer "*List of Figures*")
(setq buffer-read-only nil)
(org-mode)
(erase-buffer)
(insert (mapconcat 'identity list-of-figures ""))
(goto-char (point-min))
;; open links in the same window
(setq-local org-link-frame-setup
'((file . find-file)))
(setq buffer-read-only t)
(use-local-map (copy-keymap org-mode-map))
(local-set-key "q" #'(lambda () (interactive) (kill-buffer))))))
(org-link-set-parameters "list-of-figures"
:follow #'org-ref-list-of-figures
:export (lambda (_path _desc format)
(cond
((eq format 'latex)
(format "\\listoffigures")))))
;;** List of tables
;;;###autoload
(defun org-ref-list-of-tables (&optional _arg)
"Generate a buffer with a list of tables.
ARG does nothing."
(interactive)
(save-excursion
(widen)
(let* ((c-b (buffer-name))
(counter 0)
(list-of-tables
(org-element-map (org-ref-parse-buffer 'element) 'table
(lambda (table)
"create a link for to the table"
(save-excursion
(goto-char (org-element-property :begin table))
(when
;; ignore commented sections
(not (or (org-in-commented-heading-p)
(-intersection (org-get-tags) org-export-exclude-tags)
(looking-at "#\\+RESULTS:") ))
(cl-incf counter)
(let* ((start (org-element-property :begin table))
(linenum (progn (goto-char start) (line-number-at-pos)))
(caption (cl-caaar (org-element-property :caption table)))
(name (org-element-property :name table)))
(if caption
(format "[[file:%s::%s][Table %s:]] %s\n" c-b linenum counter caption)
;; if it has no caption, try the name
;; if it has no name, use generic name
(cond (name
(format "[[file:%s::%s][Table %s:]] %s\n"
c-b linenum counter name))
(t
(format "[[file:%s::%s][Table %s:]] No caption\n"
c-b linenum counter)))))))))))
(switch-to-buffer "*List of Tables*")
(setq buffer-read-only nil)
(org-mode)
(erase-buffer)
(insert (mapconcat 'identity list-of-tables ""))
(goto-char (point-min))
;; open links in the same window
(setq-local org-link-frame-setup
'((file . find-file)))
(setq buffer-read-only t)
(use-local-map (copy-keymap org-mode-map))
(local-set-key "q" #'(lambda () (interactive) (kill-buffer))))))
(org-link-set-parameters "list-of-tables"
:follow #'org-ref-list-of-tables
:export (lambda (_path _desc format)
(cond
((eq format 'latex)
(format "\\listoftables")))))
;;* Index link
;;
;; You need these lines in the header
;;
;; #+latex_header: \usepackage{makeidx}
;; #+latex_header: \makeindex
(org-link-set-parameters "index"
:follow (lambda (path)
(occur path))
:export (lambda (path _desc format)
(cond
((eq format 'latex)
(format "\\index{%s}" path)))))
;; this will generate a temporary index of entries in the file when clicked on.
;;;###autoload
(defun org-ref-index (&optional _path)
"Open an *index* buffer with links to index entries.
PATH is required for the org-link, but it does nothing here."
(interactive)
(let ((*index-links* '())
(*initial-letters* '()))
;; get links
(org-element-map (org-ref-parse-buffer) 'link
(lambda (link)
(let ((plist (nth 1 link)))
(when (equal (plist-get plist ':type) "index")
(add-to-list
'*index-links*
(cons (plist-get plist :path)
(format
"[[elisp:(progn (switch-to-buffer \"%s\") (goto-char %s) (org-cycle '(64)))][%s]] "
(current-buffer)
(plist-get plist :begin) ;; position of link
;; grab a description
(save-excursion
(goto-char (plist-get plist :begin))
(if (thing-at-point 'sentence)
;; get a sentence
(let ((s (thing-at-point 'sentence)))
(cl-loop for char in '("[" "]" "\n")
do
(setq s (replace-regexp-in-string
(regexp-quote char) " " s)))
(concat s " "))
;; or call it a link
"link")))))))))
;; sort the links
(setq *index-links* (cl-sort *index-links* 'string-lessp :key 'car))
;; now separate out into chunks first letters
(dolist (link *index-links*)
(push (substring (car link) 0 1) *initial-letters*))
(setq *initial-letters* (reverse *initial-letters*))
;; now create the index
(switch-to-buffer (get-buffer-create "*index*"))
(org-mode)
(erase-buffer)
(insert "#+TITLE: Index\n\n")
(dolist (letter *initial-letters*)
(insert (format "* %s\n" (upcase letter)))
;; now process the links
(while (and
*index-links*
(string= letter (substring (car (car *index-links*)) 0 1)))
(let ((link (pop *index-links*)))
(insert (format "%s %s\n\n" (car link) (cdr link))))))
(switch-to-buffer "*index*")))
(org-link-set-parameters "printindex"
:follow #'org-ref-index
:export (lambda (_path _desc format)
(cond
((eq format 'latex)
(format "\\printindex")))))
(defun org-ref-idxproc (_backend)
"Preprocess index entries.
Each entry is replaced by a radio target. The printindex is
replaced by links to them."
(let* ((index-links (reverse (org-element-map (org-element-parse-buffer) 'link
(lambda (lnk)
(when (string= "index" (org-element-property :type lnk))
lnk)))))
(sorted-groups (seq-sort-by
(lambda (x)
"Alphabetically sort groups"
(car x))
#'string-lessp
(seq-group-by
(lambda (lnk)
(org-element-property :path lnk))
index-links)))
(link-replacements '()))
;; Sort within each group
(cl-loop for (key . links) in sorted-groups do
(setf (cdr (assoc key sorted-groups))
(sort links (lambda (a b)
(< (org-element-property :begin a)
(org-element-property :begin b))))))
;; Compute replacements for each index link.
(cl-loop for (key . links) in sorted-groups do
(cl-loop for i from 0 for lnk in links do
(cl-pushnew (cons
(org-element-property :begin lnk)
(format "<<%s-%s>>" key i))
link-replacements)))
(cl-loop for il in index-links collect
(setf (buffer-substring (org-element-property :begin il)
(org-element-property :end il))
(cdr (assoc (org-element-property :begin il) link-replacements))))
;; Now we replace the printindex link
(org-element-map (org-element-parse-buffer) 'link
(lambda (lnk)
(when (string= "printindex" (org-element-property :type lnk))
(setf (buffer-substring (org-element-property :begin lnk)
(org-element-property :end lnk))
;; If sorted-groups is empty, we should do nothing I think.
(if sorted-groups
(format "*Index*\n\n%s"
(string-join
(cl-loop for (key . links) in sorted-groups collect
(format "%s: %s"
key
(string-join
(cl-loop for i from 0 for lnk in links collect
(format "[[%s-%s][%s-%s]] "
(org-element-property :path lnk)
i
(org-element-property :path lnk)
i))
", ")))
"\n\n"))
"")))))))
(provide 'org-ref-misc-links)
;;; org-ref-misc-links.el ends here

View File

@@ -0,0 +1,518 @@
;;; org-ref-natbib-bbl-citeproc.el --- A bibtex + natbib BBL-based citeproc -*- lexical-binding: t; -*-
;;
;; Copyright (C) 2021 John Kitchin
;; Author: John Kitchin <jkitchin@andrew.cmu.edu>
;; Keywords:
;; 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 <http://www.gnu.org/licenses/>.
;;
;;; Commentary:
;;
;; This is a citation processor that uses the bbl from bibtex and natbib.
;;
;; It is kind of hacky. I parse the bbl file into entries, and then replace the
;; in-text citations and the bibliography with data from the parsed bbl.
;;
;; The CSL exporter is probably better all around than this, but this does have
;; the advantage of using LaTeX/bibtex for formatting.
;;
;; TODO: pre/post notes are not handled in the bbl file. They have to be handled
;; separately
;;
;; This seems to work ok for
;; See https://gking.harvard.edu/files/natnotes2.pdf
;;
;; Basically supports stylying options in natbib including [numbers, super, authoryear] for style,
;; and [round, square, curly, angle] for in-text citations
;; and [comma, semicolon; colon] for citation separators
;; and [sort, compress, sort&compress] if you want to sort and/or compress citation numbers.
;;
;; longnamesfirst is not currently supported.
;;
;; To use this for HTML export you do something like this:
;; (let ((org-export-before-parsing-hook '(org-ref-bbl-preprocess)))
;; (org-open-file (org-html-export-to-html)))
;;
;;
;;; Code:
(defvar org-ref-natmove) ;silence compiler
(defun org-bbl-clean-string (s)
"Clean S of markups.
This replaces some LaTeX markup and bibtex markups including:
\\emph{}, \\doi{}, \\url{},\\citename, and {\\em ...} {\\bf ...},
removes things like \\protect and \\penalty0, and replaces ~ with
a space. This function is surely not complete, and it does not
cover any math (yet)."
(with-temp-buffer
(insert s)
;; I convert these to org syntax.
;; \emph... -> org italics
;; TODO This list is surely not complete.
;; convert \cmd{stuff} to the format string
(let (p1 p2 p3 p4 ss cmd-p)
(cl-loop for (cmd . repl-format) in '(("emph" . "/%s/")
("doi" . "%s")
("url" . "%s")
("citename" . "%s")
;; natexlab seems to be for differentiating similar authors.
("natexlab" . "(%s)")
;; I use \ce{} a lot, and just strip it here.
("ce" . "%s"))
do
(goto-char (point-min))
(while (search-forward (format "\\%s{" cmd) nil t)
(setq p1 (match-beginning 0)
p2 (point))
(backward-char)
(forward-list)
(setq p4 (point)
p3 (- (point) 1))
(setq s (buffer-substring p2 p3))
(cl--set-buffer-substring p1 p4 (format repl-format s))))
;; some times we have these markups TODO I bet there are more Note I use
;; non-breaking spaces here to make the org syntax ok. It doesn't seem to
;; do quite the right thing in the bib-items though.
(cl-loop for (markup . fmt) in '(("\\em" . " /%s/ ")
("\\it" . " /%s/ ")
("\\bf" . " *%s* ")
("\\tt" . " =%s= "))
do
(goto-char (point-min))
(while (search-forward (concat "{" markup) nil t)
(setq p1 (match-beginning 0)
p2 (point))
(goto-char (match-beginning 0))
(forward-list)
(setq p4 (point)
p3 (- (point) 1))
(setq ss (string-trim (buffer-substring p2 p3)))
(setf (buffer-substring p1 p4) (format fmt ss))))
;; {text} for protecting case. This is tricky to do reliably. I try to check
;; if this is not part of a command, and skip it if so. This leaves
;; un-cleaned commands in, which is desirable to me so you can see if there
;; are ones we might handle in the future.
(goto-char (point-min))
(while (search-forward "{" nil t)
;; I think if we go back a word, and are then looking back at \\, we are in a command.
;; this would fail on a latex command like \word-word{} but I can't think of any right now.
(save-excursion
(backward-word)
(setq cmd-p (looking-back "\\\\" 1)))
;; This looks back for a \cmd, basically things not a closing }
(unless cmd-p
(setq p1 (match-beginning 0)
p2 (point))
(backward-char)
(forward-list)
(setq p4 (point)
p3 (- (point) 1))
(setq s (buffer-substring p2 p3))
(cl--set-buffer-substring p1 p4 s))))
(let ((result (buffer-string)))
(cl-loop for (s . repl) in '(("~" . " ")
("\\\\&" . "&")
("\\\\protect" . "")
("\\\\penalty0" . "")
("\\\\ " . " "))
do
(setq result (replace-regexp-in-string s repl result)))
result)))
(defun org-ref-bbl-get-natbib-options ()
"Return natbib-options (including the brackets).
Defaults to [numbers,super,sort]"
(goto-char (point-min))
(if (re-search-forward "\\usepackage\\(?1:\\[.*\\]\\)?{natbib}")
(match-string 1)
"[numbers,super,sort]"))
(defun org-ref-bbl-entry (entry)
"ENTRY is a string containing the contents of a bibitem from a bbl file.
Return the bibliography string associated with the entry. This is
done in a temp-buffer so we don't actually modify the bbl file."
(with-temp-buffer
(insert (org-bbl-clean-string entry))
(goto-char (point-min))
(let (p1
p2
authors
blocks
entry)
(setq p1 (point))
(search-forward "\\newblock")
(setq p2 (match-beginning 0))
(setq authors (string-join
(mapcar 'string-trim
(split-string (buffer-substring p1 p2) "\n"))
" "))
(goto-char (- p2 1))
(while (search-forward "\\newblock" nil t)
(setq p1 (point))
(setq p2 (save-excursion
(if (search-forward "\\newblock" nil t)
(match-beginning 0)
(point-max))))
(cl-pushnew (string-join
(mapcar 'string-trim
(split-string (buffer-substring p1 p2) "\n"))
" ")
blocks))
(setq entry (string-join (append (list authors) blocks) " "))
entry)))
(defun org-ref-bbl-bibliography-data ()
"Get an p-list for each entry in the buffer.
Assumes you are in a bbl file.
Returns a plist (list bibitem-key :entry (org-ref-bbl-entry bibitem-entry)
:index counter :bracket-data bibitem-bracket)"
(let ((data '())
N ss
p1 p2 bbl-max
bibitem-bracket
bibitem-key
bibitem-entry
(counter 0))
(goto-char (point-min))
(search-forward "\\end{thebibliography}")
;; this is the character that the last line starts on.
(setq bbl-max (match-beginning 0))
(goto-char (point-min))
(when (looking-at "\\\\begin{thebibliography}{\\(?1:[0-9]*\\)}")
(setq N (string-to-number (match-string 1))))
;; This might only work for numeric types
(if (> 0 N)
(cl-loop for i from 1 to N do
(search-forward "\\bibitem[")
;; get text in [...]
(setq p1 (point))
(forward-list)
(setq p2 (point))
;; the bracket usually contains [stuff (year) more stuff]
(setq ss (org-bbl-clean-string
(buffer-substring-no-properties p1 p2)))
(let* ((s (string-match "(" ss))
(e (string-match ")" ss s)))
;; in numerical mode I think this is ignored, but we get it
;; just in case for some later day.
(setq bibitem-bracket (format "%s%s"
(substring ss 0 s)
(if (string= "()" (substring ss s (+ e 1)))
""
(concat " " (substring ss s (+ e 1)))))))
;; Now get the key. From the last
(search-forward "{")
(goto-char (match-beginning 0))
(setq p1 (+ 1 (point)))
(forward-list)
(setq p2 (- (point) 1)
bibitem-key (buffer-substring p1 p2))
;; Now get up to the next bibitem
(setq p1 (point))
(save-excursion
(setq p2 (or (when (search-forward "\\bibitem[" nil t)
(match-beginning 0))
bbl-max)))
(setq bibitem-entry (string-trim (buffer-substring p1 p2)))
(cl-pushnew (list bibitem-key :entry (org-ref-bbl-entry bibitem-entry)
:index i :bracket-data bibitem-bracket)
data))
;; no number found probably author year
(while (search-forward "\\bibitem[" nil t)
(cl-incf counter)
;; get text in [...]
(setq p1 (point))
(search-forward "]")
(backward-char)
(setq p2 (point))
(setq ss (org-bbl-clean-string
(buffer-substring-no-properties p1 p2)))
(let* ((s (string-match "(" ss))
(e (string-match ")" ss s)))
(setq bibitem-bracket (format "%s%s"
(substring ss 0 s)
(if (string= "()" (substring ss s (+ e 1)))
""
(concat " " (substring ss s (+ e 1)))))))
;; Now get the key. From the last
(search-forward "{")
(goto-char (match-beginning 0))
(setq p1 (+ 1 (point)))
(forward-list)
(setq p2 (- (point) 1)
bibitem-key (buffer-substring p1 p2))
;; Now get up to the next bibitem
(setq p1 (point))
(save-excursion
(setq p2 (or (when (search-forward "\\bibitem[" nil t)
(match-beginning 0))
bbl-max)))
(setq bibitem-entry (string-trim (buffer-substring p1 p2)))
(cl-pushnew (list bibitem-key :entry (org-ref-bbl-entry bibitem-entry)
:index counter :bracket-data bibitem-bracket)
data)))
(reverse data)))
(defun org-ref-bbl-compress-numbers (lst)
"Take a list like (1 2 3 6) and return \"1-3,6\"."
(let* ((a (pop lst))
b
(sequence (list a))
(sequentials '()))
(while lst
(setq b (pop lst))
(if (= (- b a) 1)
;; we have a sequence, add it, set a=b and continue
(setq sequence (append sequence (list b))
a b)
;; lost sequence, store the sequence
(setq sequentials (append sequentials (list sequence))
sequence (list b)
a b)))
;; store last one
(setq sequentials (append sequentials (list sequence)))
;; Now construct strings for each group
(cl-loop for group in sequentials collect
(pcase (length group)
(1 (format "[[%s]]" (car group)))
(2 (format "[[%s]],[[%s]]" (cl-first group) (cl-second group)))
(_ (format "[[%s]]-[[%s]]" (cl-first group) (car (last group))))))))
(defun org-ref-replace-cite-link (link bibdata NATBIB-OPTIONS backend)
"NATBIB-OPTIONS is the string to options.
Argument LINK is an org link for a citation.
Argument BIBDATA the data parsed from a bbl file.
Argument BACKEND is the export format."
(let* ((refs (plist-get (org-ref-parse-cite-path (org-element-property :path link)) :references))
(keys (cl-loop for ref in refs collect (plist-get ref :key)))
items replacements replacement joiner p1 p2)
;; Numeric types
(cond
((or (string-match-p "numbers" NATBIB-OPTIONS)
(string-match-p "super" NATBIB-OPTIONS))
(setq items (cl-loop for key in keys
collect (plist-get (cdr (assoc key bibdata)) :index)))
(when (string-match-p "sort" NATBIB-OPTIONS)
(setq items (sort items #'<)))
(setq replacements (if (string-match-p "compress" NATBIB-OPTIONS)
(org-ref-bbl-compress-numbers items)
;; these are fuzzy org links to the target in item.
(cl-loop for item in items collect (format "[[%s]]" item)))))
;; authoryear types
;; This html provides an anchor that is named. Targets are usually replaced with numbers, not the text.
((string-match-p "authoryear" NATBIB-OPTIONS)
(setq replacements (cl-loop for key in keys
collect
(cond
((eq backend 'html)
(format "@@html:<a href=\"#%s\">%s</a>@@"
(plist-get (cdr (assoc key bibdata)) :bracket-data)
(plist-get (cdr (assoc key bibdata)) :bracket-data)))
(t
(format "[[%s]]" (plist-get (cdr (assoc key bibdata)) :bracket-data)))))))
(t
(error "%s not supported yet" NATBIB-OPTIONS)))
;; Now join all the replacements for each reference
(setq joiner (cond
((string-match-p "comma" NATBIB-OPTIONS)
",")
((or (string-match-p "semicolon" NATBIB-OPTIONS)
(string-match-p "colon" NATBIB-OPTIONS))
";")
(t
";")))
;; Finally create the overall replacement
(setq replacement (cond
((string-match-p "super" NATBIB-OPTIONS)
(format "^{%s}" (string-join replacements joiner)))
((string-match-p "square" NATBIB-OPTIONS)
(format "[%s]" (string-join replacements joiner)))
((string-match-p "round" NATBIB-OPTIONS)
(format "(%s)" (string-join replacements joiner)))
((string-match-p "curly" NATBIB-OPTIONS)
(format "{%s}" (string-join replacements joiner)))
((string-match-p "angle" NATBIB-OPTIONS)
(format "<%s>" (string-join replacements joiner)))
((string-match-p "authoryear" NATBIB-OPTIONS)
(string-join replacements joiner))
(t
(error "Cannot compute replacement for %s" NATBIB-OPTIONS))))
;; When super is the style, we need to replace any blanks back to the last
;; non-space. We just look back and move point if needed here.
(if (not (string-match-p "super" NATBIB-OPTIONS))
(setq p1 (org-element-property :begin link))
(goto-char (org-element-property :begin link))
(while (looking-back " " 1)
(backward-char))
(setq p1 (point)))
(setq p2 (org-element-property :end link))
;; org-ref-natmove is dynamically bound here
(when org-ref-natmove
(save-excursion
(goto-char (org-element-property :end link))
(skip-chars-backward " ")
(when (string-match-p "[[:punct:]]" (buffer-substring (point) (+ (point) 1)))
;; Get the character
(setq replacement (concat (buffer-substring (org-element-property :end link)
(+ 1 (org-element-property :end link)))
replacement)
p2 (+ 1 (org-element-property :end link))))))
(setf (buffer-substring p1 p2)
(concat replacement (make-string (org-element-property :post-blank link) ? )))))
(defun org-ref-bbl-replace-bibliography (bib-link bibdata NATBIB-OPTIONS backend)
"Get a replacement bibliography string for BIBDATA and NATBIB-OPTIONS.
BIBDATA comes from `org-ref-bbl-bibliography-data'.
Argument BIB-LINK an org link for a bibliography.
Argument BACKEND is the export format."
(cl--set-buffer-substring (org-element-property :begin bib-link)
(org-element-property :end bib-link)
(cond
((or (string-match-p "numbers" NATBIB-OPTIONS)
(string-match-p "super" NATBIB-OPTIONS))
(concat "\n* Bibliography\n\n"
(string-join
(cl-loop for entry in bibdata collect
(format "%s. <<%s>> %s"
(plist-get (cdr entry) :index)
(plist-get (cdr entry) :index)
(plist-get (cdr entry) :entry)))
"\n\n")))
((string-match-p "authoryear" NATBIB-OPTIONS)
(concat "\n* Bibliography\n\n"
(string-join
(cl-loop for entry in bibdata collect
(cond
((eq backend 'html)
(format "- @@html:<a id=\"%s\"></a>@@(%s) %s\n"
(plist-get (cdr entry) :bracket-data)
(plist-get (cdr entry) :bracket-data)
(plist-get (cdr entry) :entry)))
(t
(format "- <<%s>> %s"
(plist-get (cdr entry) :bracket-data)
(plist-get (cdr entry) :entry)))))
"\n")))
(t
(error "%s not supported yet" NATBIB-OPTIONS)))))
(defun org-ref-bbl-preprocess (&optional backend)
"Should work on a copy of the buffer.
Meant to be used in `org-export-before-parsing-hook'.
Optional argument BACKEND The export backend.
You need a LaTeX file and a bbl file for it. This hook generates
those, then gets the data, replaces the citations and the
bibliography.
"
(let* ((org-export-before-parsing-hook nil)
(tex-file (org-latex-export-to-latex))
(bbl-file (concat (file-name-sans-extension tex-file) ".bbl"))
natbib-options bibdata org-ref-natmove
buf)
(when-let (buf (find-buffer-visiting tex-file))
(kill-buffer buf))
(when-let (buf (find-buffer-visiting bbl-file))
(kill-buffer buf))
;; refresh these
(call-process-shell-command (format "latex -shell-escape %s" tex-file))
(call-process-shell-command (format "bibtex %s" (file-name-sans-extension tex-file)))
(setq buf (find-file-noselect tex-file))
(with-current-buffer buf
(goto-char (point-min))
(setq natbib-options (org-ref-bbl-get-natbib-options))
(goto-char (point-min))
(setq org-ref-natmove (search-forward "\\usepackage{natmove}" nil t)))
(kill-buffer buf)
(setq buf (find-file-noselect bbl-file))
(with-current-buffer buf
(goto-char (point-min))
(setq bibdata (org-ref-bbl-bibliography-data)))
(kill-buffer buf)
;; Replace all the cite links
(cl-loop for cl in (reverse (org-ref-get-cite-links)) do
(org-ref-replace-cite-link cl bibdata natbib-options backend))
(org-ref-bbl-replace-bibliography
(org-element-map (org-element-parse-buffer) 'link
(lambda (lnk)
(when (string= (org-element-property :type lnk) "bibliography")
lnk))
nil
t)
bibdata natbib-options backend)))
(provide 'org-ref-natbib-bbl-citeproc)
;;; org-ref-natbib-bbl-citeproc.el ends here

View File

@@ -1,6 +1,6 @@
;;; org-ref-pdf.el --- Drag-n-drop PDF onto bibtex files -*- lexical-binding: t; -*-
;; Copyright (C) 2015 John Kitchin
;; Copyright (C) 2015-2021 John Kitchin
;; Author: John Kitchin <jkitchin@andrew.cmu.edu>
;; Keywords:
@@ -22,36 +22,31 @@
;; This library provides functions to enable drag-n-drop of pdfs onto a bibtex
;; buffer to add bibtex entries to it.
;;
;; [2021-08-29 Sun] I have not found drag-and-drop to be especially reliable,
;; and don't recommend you use it. This code relies 'pdf-tools, which is slow to
;; load for me. pdf-tools is no longer automatically installed, so if you use
;; this, you should install it yourself.
;; TODO: If no DOI is found, figure out a way to do a crossref/google query to
;; get a doi. This needs a reliable title/citation.
;;; Code:
(require 'pdf-tools)
(require 'f)
;; [2019-10-13 Sun] I am commenting this out for now. I added it for some
;; reason, but I cannot figure out why. It is pretty slow to load, so since I
;; don't know why it is here, I am commenting it out until it is obvious again.
;; (require 'pdf-tools)
(eval-when-compile
(require 'cl-lib))
(declare-function org-ref-bibtex-key-from-doi "org-ref-bibtex.el")
;; See https://github.com/jkitchin/org-ref/issues/812
;; apparently there is a function name change coming in
;; (if (and (not (fboundp 'dnd-unescape-uri))
;; (fboundp 'dnd--escape-uri))
;; (defalias 'dnd-unescape-uri 'dnd--unescape-uri)
;; (warn "dnd-unescape-uri is undefined. Some things may not work."))
(defgroup org-ref-pdf nil
"Customization group for org-ref-pdf"
:tag "Org Ref PDF"
:group 'org-ref-pdf)
(defcustom pdftotext-executable
"pdftotext"
"Executable for pdftotext. Set if the executable is not on your
@@ -59,18 +54,21 @@ path, or you want to use another version."
:type 'file
:group 'org-ref-pdf)
(defcustom org-ref-pdf-doi-regex
"10\\.[0-9]\\{4,9\\}/[-+._;()/:A-Z0-9]+"
"Regular expression to match DOIs in a pdf converted to text."
:type 'regexp
:group 'org-ref-pdf)
(defcustom org-ref-pdf-to-bibtex-function
'copy-file
"Function for getting a pdf to the `org-ref-pdf-directory'.
"Function for getting a pdf to a directory.
Defaults to `copy-file', but could also be `rename-file'."
:type 'File :group 'org-ref-pdf)
(defun org-ref-extract-doi-from-pdf (pdf)
"Try to extract a doi from a PDF file.
There may be more than one doi in the file. This function returns
@@ -79,13 +77,11 @@ bracket, space or end of line. dx.doi.org/up to a quote, bracket,
space or end of line.
If there is a trailing . we chomp it off. Returns a list of doi
strings, or nil.
"
strings, or nil."
(with-temp-buffer
(insert (shell-command-to-string (format "%s %s -"
pdftotext-executable
(shell-quote-argument (dnd-unescape-uri pdf)))))
(shell-quote-argument pdf))))
(goto-char (point-min))
(let ((matches '()))
(while (re-search-forward org-ref-pdf-doi-regex nil t)
@@ -99,30 +95,36 @@ strings, or nil.
(defun org-ref-pdf-doi-candidates (dois)
"Generate candidate list for helm source.
"Generate candidate list for a completion source.
Used when multiple dois are found in a pdf file."
(cl-loop for doi in dois
collect
(condition-case nil
(cons
(plist-get (doi-utils-get-json-metadata doi) :title)
doi)
(error (cons (format "%s read error" doi) doi)))))
collect
(condition-case nil
(cons
(plist-get (doi-utils-get-json-metadata doi) :title)
doi)
(error (cons (format "%s read error" doi) doi)))))
(defun org-ref-pdf-add-dois (_)
"Add all entries for CANDIDATE in `helm-marked-candidates'."
(cl-loop for doi in (helm-marked-candidates)
do
(doi-utils-add-bibtex-entry-from-doi
doi
(buffer-file-name))))
(defun org-ref-bibtex-key-from-doi (doi)
"Return a bibtex entry's key from a DOI.
BIB is an optional filename to get the entry from."
(catch 'key
(cl-loop for bibfile in (if (stringp bibtex-completion-bibliography)
(list bibtex-completion-bibliography)
bibtex-completion-bibliography)
do
(with-temp-buffer
(insert-file-contents (expand-file-name bibfile))
(when (search-forward doi)
(bibtex-beginning-of-entry)
(throw 'key (cdr (assoc "=key=" (bibtex-parse-entry)))))))))
;;;###autoload
(defun org-ref-pdf-to-bibtex ()
"Add pdf of current buffer to bib file and save pdf to
`org-ref-default-bibliography'. The pdf should be open in Emacs
using the `pdf-tools' package."
"Add pdf of current buffer to bib file and save pdf. The pdf
should be open in Emacs using the `pdf-tools' package."
(interactive)
(when (not (f-ext? (downcase (buffer-file-name)) "pdf"))
(error "Buffer is not a pdf file"))
@@ -134,127 +136,19 @@ using the `pdf-tools' package."
(completing-read "Select DOI: " dois))))
;; Add bib entry from doi:
(doi-utils-add-bibtex-entry-from-doi doi)
;; Copy pdf to `org-ref-pdf-directory':
;; Copy pdf to a directory
(let ((key (org-ref-bibtex-key-from-doi doi)))
(funcall org-ref-pdf-to-bibtex-function
(buffer-file-name)
(expand-file-name (format "%s.pdf" key)
org-ref-pdf-directory)))))
;;;###autoload
;; (defun org-ref-pdf-dnd-func (event)
;; "Drag-n-drop support to add a bibtex entry from a pdf file."
;; (interactive "e")
;; (goto-char (nth 1 (event-start event)))
;; (x-focus-frame nil)
;; (let* ((payload (car (last event)))
;; (pdf (cadr payload))
;; (dois (org-ref-extract-doi-from-pdf pdf)))
;; (cond
;; ((null dois)
;; (message "No doi found in %s" pdf))
;; ((= 1 (length dois))
;; (doi-utils-add-bibtex-entry-from-doi
;; (car dois)
;; (buffer-file-name)))
;; ;; Multiple DOIs found
;; (t
;; (helm :sources `((name . "Select a DOI")
;; (candidates . ,(org-ref-pdf-doi-candidates dois))
;; (action . org-ref-pdf-add-dois)))))))
;; This isn't very flexible, as it hijacks all drag-n-drop events. I switched to
;; using `dnd-protocol-alist'.
;; (define-key bibtex-mode-map (kbd "<drag-n-drop>") 'org-ref-pdf-dnd-func)
;; This is what the original dnd function was.
;; (define-key bibtex-mode-map (kbd "<drag-n-drop>") 'ns-drag-n-drop)
;; I replaced the functionality above with this new approach that leverages
;; ns-drag-n-drop. An alternative approach would be to adapt the function above
;; so that if the item dragged on wasn't a pdf, it would use another function.
;; that is essentially what ns-drag-n-drop enables, multiple handlers for
;; different uris that get dropped on the windwo.
(defun org-ref-pdf-dnd-protocol (uri action)
"Drag-n-drop protocol.
PDF will be a string like file:path.
ACTION is what to do. It is required for `dnd-protocol-alist'.
This function should only apply when in a bibtex file."
(if (and (buffer-file-name)
(f-ext? (buffer-file-name) "bib"))
(let* ((path (substring uri 5))
dois)
(cond
((f-ext? path "pdf")
(setq dois (org-ref-extract-doi-from-pdf
path))
(cond
((null dois)
(message "No doi found in %s" path)
nil)
((= 1 (length dois))
;; we do not need to get the pdf, since we have one.
(let ((doi-utils-download-pdf nil))
(doi-utils-add-bibtex-entry-from-doi
(car dois)
(buffer-file-name))
;; we should copy the pdf to the pdf directory though
(let ((key (cdr (assoc "=key=" (bibtex-parse-entry)))))
(copy-file (dnd-unescape-uri path) (expand-file-name (format "%s.pdf" key) org-ref-pdf-directory))))
action)
;; Multiple DOIs found
(t
(helm :sources `((name . "Select a DOI")
(candidates . ,(org-ref-pdf-doi-candidates dois))
(action . org-ref-pdf-add-dois)))
action)))
;; drag a bib file on and add contents to the end of the file.
((f-ext? path "bib")
(goto-char (point-max))
(insert "\n")
(insert-file-contents path))))
;; ignoring. pass back to dnd. Copied from `org-download-dnd'. Apparently
;; returning nil does not do this.
(let ((dnd-protocol-alist
(rassq-delete-all
'org-ref-pdf-dnd-protocol
(copy-alist dnd-protocol-alist))))
(dnd-handle-one-url nil action uri))))
(add-to-list 'dnd-protocol-alist '("^file:" . org-ref-pdf-dnd-protocol))
;;;###autoload
(defun org-ref-pdf-dir-to-bibtex (bibfile directory)
"Create BIBFILE from pdf files in DIRECTORY."
(interactive (list
(read-file-name "Bibtex file: ")
(read-directory-name "Directory: ")))
(find-file bibfile)
(goto-char (point-max))
(cl-loop for pdf in (f-entries directory (lambda (f) (f-ext? f "pdf")))
do
(goto-char (point-max))
(let ((dois (org-ref-extract-doi-from-pdf pdf)))
(cond
((null dois)
(insert (format "%% No doi found to create entry in %s.\n" pdf)))
((= 1 (length dois))
(doi-utils-add-bibtex-entry-from-doi
(car dois)
(buffer-file-name))
(bibtex-beginning-of-entry)
(insert (format "%% [[file:%s]]\n" pdf)))
;; Multiple DOIs found
(t
(insert (format "%% Multiple dois found in %s\n" pdf))
(helm :sources `((name . "Select a DOI")
(candidates . ,(org-ref-pdf-doi-candidates dois))
(action . org-ref-pdf-add-dois))))))))
(cond
((stringp bibtex-completion-library-path)
bibtex-completion-library-path)
((and (listp bibtex-completion-library-path)
(= 1 (length bibtex-completion-library-path)))
(car bibtex-completion-library-path))
(t
(completing-read "Dir: " bibtex-completion-library-path))))))))
;;;###autoload

View File

@@ -1,15 +1,13 @@
(define-package "org-ref" "1.1.1" "citations, cross-references and bibliographies in org-mode"
'((dash "2.11.0")
(htmlize "1.51")
(helm "1.5.5")
(helm-bibtex "2.0.0")
(ivy "0.8.0")
(hydra "0.13.2")
(key-chord "0")
(s "1.10.0")
(f "0.18.0")
(emacs "24.4")
(pdf-tools "0.7")))
(define-package "org-ref" "3.0.0" "citations, cross-references and bibliographies in org-mode"
'((dash "0")
(s "0")
(f "0")
(hydra "0")
(htmlize "0")
(parsebib "0")
(bibtex-completion "0")
(emacs "26")))
;; Local Variables:
;; no-byte-compile: t

View File

@@ -1,15 +1,14 @@
(define-package "org-ref" "20210108.1415" "citations, cross-references and bibliographies in org-mode"
'((dash "2.11.0")
(htmlize "1.51")
(helm "1.5.5")
(helm-bibtex "2.0.0")
(ivy "0.8.0")
(hydra "0.13.2")
(key-chord "0")
(s "1.10.0")
(f "0.18.0")
(pdf-tools "0.7"))
:commit "cae67aa7fcaced2112152a343d35ff308a54c4c1" :authors
(define-package "org-ref" "20220101.1941" "citations, cross-references and bibliographies in org-mode"
'((dash "0")
(s "0")
(f "0")
(htmlize "0")
(hydra "0")
(avy "0")
(parsebib "0")
(bibtex-completion "0")
(citeproc "0"))
:commit "429733150548a847966685680bca0a20ec3b1ad9" :authors
'(("John Kitchin" . "jkitchin@andrew.cmu.edu"))
:maintainer
'("John Kitchin" . "jkitchin@andrew.cmu.edu")

View File

@@ -1,6 +1,6 @@
;;; org-ref-pubmed.el --- Links and functions for Pubmed and NIH databases -*- lexical-binding: t; -*-
;; Copyright (C) 2015 John Kitchin
;; Copyright (C) 2015-2021 John Kitchin
;; Author: John Kitchin <jkitchin@andrew.cmu.edu>
;; Keywords: convenience
@@ -53,15 +53,15 @@
(require 'org)
(require 'org-ref-utils)
(org-ref-link-set-parameters "pmid"
:follow (lambda (link-string) (browse-url (format "http://www.ncbi.nlm.nih.gov/pubmed/%s" link-string)))
:export (lambda (keyword desc format)
(cond
((eq format 'html)
(format "<a href=\"http://www.ncbi.nlm.nih.gov/pmc/articles/mid/%s\">pmid:%s</a>" keyword (or desc keyword))) ; no output for html
((eq format 'latex)
;; write out the latex command
(format "\\url{http://www.ncbi.nlm.nih.gov/pmc/articles/mid/%s}{%s}" keyword (or desc keyword))))))
(org-link-set-parameters "pmid"
:follow (lambda (link-string) (browse-url (format "http://www.ncbi.nlm.nih.gov/pubmed/%s" link-string)))
:export (lambda (keyword desc format)
(cond
((eq format 'html)
(format "<a href=\"http://www.ncbi.nlm.nih.gov/pmc/articles/mid/%s\">pmid:%s</a>" keyword (or desc keyword))) ; no output for html
((eq format 'latex)
;; write out the latex command
(format "\\url{http://www.ncbi.nlm.nih.gov/pmc/articles/mid/%s}{%s}" keyword (or desc keyword))))))
;;** Get MEDLINE metadata
@@ -72,16 +72,15 @@
"Get MEDLINE text for PMID as a string."
(with-current-buffer
(url-retrieve-synchronously
(format "http://www.ncbi.nlm.nih.gov/pubmed/%s/?report=medline&format=text" pmid))
(format "https://pubmed.ncbi.nlm.nih.gov/%s/?format=pubmed" pmid))
(goto-char (point-min))
(let ((p1 (search-forward "<pre>"))
(let ((p1 (search-forward "<pre class=\"article-details\" id=\"article-details\">"))
(p2 (search-forward "</pre>")))
(buffer-substring (+ 1 p1) (- p2 6)))))
(replace-regexp-in-string "
" "" (buffer-substring (+ 1 p1) (- p2 6))))))
;;** Parse the PMID MEDLINE data
;; We can parse this into a data structure.
(defun pubmed-parse-medline (pmid)
"Parse the medline text for PMID and return a list of cons cells."
@@ -153,31 +152,6 @@ You must clean the entry after insertion."
You must clean the entry after insertion."
(interactive "sPMID: ")
(insert (pubmed-pmid-to-bibtex pmid)))
;;** PMID to xml
;; We can also get xml of the MEDLINE data. The web page here also wraps the xml
;; in a <pre> block and escapes the <> with &lt; and &gt;, which we have to
;; undo. I have not used this code for anything, so I am not sure how good the
;; xml code is.
;;;###autoload
(defun pubmed-get-medline-xml (pmid)
"Get MEDLINE xml for PMID as a string."
(interactive)
(with-current-buffer
(url-retrieve-synchronously
(format "http://www.ncbi.nlm.nih.gov/pubmed/%s/?report=xml&format=text" pmid))
(goto-char (point-min))
(while (search-forward "&lt;" nil t)
(replace-match "<"))
(goto-char (point-min))
(while (search-forward "&gt;" nil t)
(replace-match ">"))
(goto-char (point-min))
(let ((p1 (search-forward "<pre>"))
(p2 (search-forward "</pre>")))
(buffer-substring (+ 1 p1) (- p2 6)))))
;;* Pubmed Central (PMC) link
@@ -190,14 +164,14 @@ You must clean the entry after insertion."
;; Here we define a new link. Clicking on it simply opens a webpage to the
;; article.
(org-ref-link-set-parameters "pmcid"
:follow (lambda (link-string) (browse-url (format "http://www.ncbi.nlm.nih.gov/pmc/articles/%s" link-string)))
:export (lambda (keyword desc format)
(cond
((eq format 'html)
(format "<a href=\"http://www.ncbi.nlm.nih.gov/pmc/articles/%s\">pmcid:%s</a>" keyword (or desc keyword)))
((eq format 'latex)
(format "\\url{http://www.ncbi.nlm.nih.gov/pmc/articles/%s}{%s}" keyword (or desc keyword))))))
(org-link-set-parameters "pmcid"
:follow (lambda (link-string) (browse-url (format "http://www.ncbi.nlm.nih.gov/pmc/articles/%s" link-string)))
:export (lambda (keyword desc format)
(cond
((eq format 'html)
(format "<a href=\"http://www.ncbi.nlm.nih.gov/pmc/articles/%s\">pmcid:%s</a>" keyword (or desc keyword)))
((eq format 'latex)
(format "\\url{http://www.ncbi.nlm.nih.gov/pmc/articles/%s}{%s}" keyword (or desc keyword))))))
;;* NIHMSID
@@ -208,15 +182,15 @@ You must clean the entry after insertion."
;; article. Once the Web version of the NIHMS submission is approved for
;; inclusion in PMC and the corresponding citation is in PubMed, the article
;; will also be assigned a PMCID.
(org-ref-link-set-parameters "nihmsid"
:follow (lambda (link-string) (browse-url (format "http://www.ncbi.nlm.nih.gov/pmc/articles/mid/%s" link-string)))
:export (lambda (keyword desc format)
(cond
((eq format 'html)
(format "<a href=\"http://www.ncbi.nlm.nih.gov/pmc/articles/mid//%s\">nihmsid:%s</a>" keyword (or desc keyword)))
((eq format 'latex)
;; write out the latex command
(format "\\url{http://www.ncbi.nlm.nih.gov/pmc/articles/mid/%s}{%s}" keyword (or desc keyword))))))
(org-link-set-parameters "nihmsid"
:follow (lambda (link-string) (browse-url (format "http://www.ncbi.nlm.nih.gov/pmc/articles/mid/%s" link-string)))
:export (lambda (keyword desc format)
(cond
((eq format 'html)
(format "<a href=\"http://www.ncbi.nlm.nih.gov/pmc/articles/mid//%s\">nihmsid:%s</a>" keyword (or desc keyword)))
((eq format 'latex)
;; write out the latex command
(format "\\url{http://www.ncbi.nlm.nih.gov/pmc/articles/mid/%s}{%s}" keyword (or desc keyword))))))
@@ -243,17 +217,17 @@ You must clean the entry after insertion."
(browse-url
(format "http://www.ncbi.nlm.nih.gov/pubmed/?term=%s" (url-hexify-string query))))
(org-ref-link-set-parameters "pubmed-search"
:follow (lambda (query)
"Open QUERY in a `pubmed-simple-search'."
(pubmed-simple-search query))
:export (lambda (query desc format)
(let ((url (format "http://www.ncbi.nlm.nih.gov/pubmed/?term=%s" (url-hexify-string query))))
(cond
((eq format 'html)
(format "<a href=\"%s\">%s</a>" url (or desc (concat "pubmed-search:" query))))
((eq format 'latex)
(format "\\href{%s}{%s}" url (or desc (concat "pubmed-search:" query))))))))
(org-link-set-parameters "pubmed-search"
:follow (lambda (query)
"Open QUERY in a `pubmed-simple-search'."
(pubmed-simple-search query))
:export (lambda (query desc format)
(let ((url (format "http://www.ncbi.nlm.nih.gov/pubmed/?term=%s" (url-hexify-string query))))
(cond
((eq format 'html)
(format "<a href=\"%s\">%s</a>" url (or desc (concat "pubmed-search:" query))))
((eq format 'latex)
(format "\\href{%s}{%s}" url (or desc (concat "pubmed-search:" query))))))))
;; ** Pubmed clinical
@@ -272,20 +246,20 @@ You must clean the entry after insertion."
(browse-url
(format "https://www.ncbi.nlm.nih.gov/pubmed/clinical?term=%s" (url-hexify-string query))))
(org-ref-link-set-parameters "pubmed-clinical"
:follow (lambda (query)
"Open QUERY in a `pubmed-clinical-search'."
(pubmed-clinical-search query))
:export (lambda (query desc format)
(let ((url (format "http://www.ncbi.nlm.nih.gov/pubmed/clinical?term=%s"
(url-hexify-string query))))
(cond
((eq format 'html)
(format "<a href=\"%s\">%s</a>" url
(or desc (concat "pubmed-clinical-search:" query))))
((eq format 'latex)
(format "\\href{%s}{%s}" url
(or desc (concat "pubmed-clinical-search:" query))))))))
(org-link-set-parameters "pubmed-clinical"
:follow (lambda (query)
"Open QUERY in a `pubmed-clinical-search'."
(pubmed-clinical-search query))
:export (lambda (query desc format)
(let ((url (format "http://www.ncbi.nlm.nih.gov/pubmed/clinical?term=%s"
(url-hexify-string query))))
(cond
((eq format 'html)
(format "<a href=\"%s\">%s</a>" url
(or desc (concat "pubmed-clinical-search:" query))))
((eq format 'latex)
(format "\\href{%s}{%s}" url
(or desc (concat "pubmed-clinical-search:" query))))))))

View File

@@ -0,0 +1,555 @@
;;; org-ref-ref-links.el --- cross-reference links for org-ref -*- lexical-binding: t; -*-
;;
;; Copyright (C) 2021 John Kitchin
;; Author: John Kitchin <jkitchin@andrew.cmu.edu>
;; Keywords: convenience
;; 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 <http://www.gnu.org/licenses/>.
;;
;;; Commentary:
;;
;;; Code:
(eval-and-compile (require 'org-macs))
(require 'hydra)
(defcustom org-ref-default-ref-type "ref"
"Default ref link type to use when inserting ref links."
:type 'string
:group 'org-ref)
(defface org-ref-ref-face
`((t (:inherit org-link :foreground "dark red")))
"Face for ref links in org-ref."
:group 'org-ref-faces)
(defvar org-ref-label-re
(rx (group-n 1 (one-or-more (any word "-.:?!`'/*@+|(){}<>&_^$#%~"))))
"Regexp for labels.")
(defvar org-ref-label-link-re
(rx "label:" (group-n 1 (one-or-more (any word "-.:?!`'/*@+|(){}<>&_^$#%~"))))
"Regexp for label links.")
(defvar org-ref-ref-label-regexps
(list
(concat ":ID:\\s-+" org-ref-label-re "\\_>")
;; CUSTOM_ID in a heading
(concat ":CUSTOM_ID:\\s-+" org-ref-label-re "\\_>")
;; #+name
(concat "^\\s-*#\\+name:\\s-+" org-ref-label-re "\\_>")
;; labels in latex
(concat "\\\\label{" org-ref-label-re "}")
;; A target, code copied from org-target-regexp and group 1 numbered.
(let ((border "[^<>\n\r \t]"))
(format "<<\\(?1:%s\\|%s[^<>\n\r]*%s\\)>>"
border border border))
;; A label link
(concat "label:" org-ref-label-re "\\_>")
"\\\\lstset{.*label=\\(?1:.*?\\),.*}")
"List of regular expressions to labels.
The label should always be in group 1.")
(defvar org-ref-ref-types
'(("ref" "A regular cross-reference to a label")
("eqref" "A cross-reference to an equation")
("pageref" "to the page number a label is on")
("nameref" "to the name associated with a label (e.g. a caption)")
("autoref" "from hyperref, adds automatic prefixes")
("cref" "from cleveref, adds automatic prefixes, and condenses multiple refs")
("Cref" "from cleveref, capitalized version of cref")
("crefrange" "from cleveref, makes a range of refs from two refs with a prefix")
("Crefrange" "from cleveref, capitalized prefix version of crefrange"))
"List of ref link types (type description).")
(defun org-ref-select-ref-type ()
"Select a ref type with annotated completion."
(let* ((type-annotation (lambda (s)
(let ((item (assoc s minibuffer-completion-table)))
(when item (concat
(make-string (- 12 (length s)) ? )
"-- "
(cl-second item))))))
(completion-extra-properties `(:annotation-function ,type-annotation)))
(completing-read "Type: " org-ref-ref-types)))
(defun org-ref-change-ref-type (new-type)
"Change the ref type to NEW-TYPE."
(interactive (list (org-ref-select-ref-type)))
(let* ((cite-link (org-element-context))
(old-type (org-element-property :type cite-link))
(begin (org-element-property :begin cite-link))
(end (org-element-property :end cite-link))
(bracketp (eq 'bracket (org-element-property :format cite-link)))
(path (org-element-property :path cite-link))
(deltap (- (point) begin)))
;; note this does not respect brackets
(setf (buffer-substring begin end)
(concat
(if bracketp "[[" "")
new-type ":" path
(if bracketp "]]" "")))
;; try to preserve the character the point is on.
(goto-char (+ begin deltap (- (length new-type) (length old-type))))))
(defun org-ref-get-labels ()
"Return a list of referenceable labels in the document.
You can reference:
A NAME keyword
A CUSTOM_ID property on a heading
A LaTeX label
A target.
A label link
A setting in lstset
See `org-ref-ref-label-regexps' for the patterns that find these.
Returns a list of cons cells (label . context).
It is important for this function to be fast, since we use it in
font-lock."
(let ((case-fold-search t)
(rx (string-join org-ref-ref-label-regexps "\\|"))
(labels '())
context)
(save-excursion
(org-with-wide-buffer
(goto-char (point-min))
(while (re-search-forward rx nil t)
(setq context (buffer-substring
(save-excursion (forward-line -1) (point))
(save-excursion (forward-line +2) (point))))
(cl-pushnew (cons (match-string-no-properties 1) context)
labels))))
;; reverse so they are in the order we find them.
(delete-dups (reverse labels))))
(defun org-ref-ref-jump-to (&optional path)
"Jump to the target for the ref link at point."
(interactive)
(let ((case-fold-search t)
(label (get-text-property (point) 'org-ref-ref-label))
(labels (split-string path ","))
(rx (string-join org-ref-ref-label-regexps "\\|")))
(when (null label)
(pcase (length labels)
(1
(setq label (cl-first labels)))
(_
(setq label (completing-read "Label: " labels)))))
(when label
(org-mark-ring-push)
(widen)
(goto-char (point-min))
(catch 'found
(while (re-search-forward rx)
(when (string= label (match-string-no-properties 1))
(save-match-data (org-mark-ring-push))
(goto-char (match-beginning 1))
(org-show-entry)
(substitute-command-keys
"Go back with (org-mark-ring-goto) \`\\[org-mark-ring-goto]'.")
(throw 'found t)))))))
(defun org-ref-ref-help-echo (_win _obj position)
"Tooltip for context on a ref label.
POSITION is the point under the mouse I think."
(cdr (assoc (get-text-property position 'org-ref-ref-label) (org-ref-get-labels))))
(defun org-ref-ref-activate (start _end path _bracketp)
"Activate a ref link.
The PATH should be a comma-separated list of labels.
Argument START is the start of the link.
Argument END is the end of the link."
(let ((labels (mapcar 'car (org-ref-get-labels))))
(goto-char start)
(cl-loop for label in (split-string path ",") do
(search-forward label)
;; store property so we can follow it later.
(put-text-property (match-beginning 0)
(match-end 0)
'org-ref-ref-label
label)
(unless (member label labels)
(put-text-property (match-beginning 0)
(match-end 0)
'face
'font-lock-warning-face)
(put-text-property (match-beginning 0)
(match-end 0)
'help-echo
"Label not found")))))
(defun org-ref-ref-export (cmd keyword _desc backend)
"An export function for ref links.
Argument CMD is the LaTeX command to export to.
Argument KEYWORD is the path of the ref link.
Argument BACKEND is the export backend.
This is meant to be used with `apply-partially' in the link definitions."
(cond
((eq backend 'latex)
(format "\\%s{%s}" cmd keyword))))
(defun org-ref-complete-link (refstyle &optional _arg)
"Complete a ref link to an existing label."
(concat refstyle ":" (completing-read "Label: " (org-ref-get-labels))))
(defun org-ref-store-ref ()
"Store a ref link to a label. The output will be a ref to that label."
;; First we have to make sure we are on a label link.
(let* ((object (and (eq major-mode 'org-mode) (org-element-context)))
(label (cond
;; here literally on a label link.
((and
(equal (org-element-type object) 'link)
(equal (org-element-property :type object) "label"))
(org-element-property :path object))
;; here on a file link. if it has a caption with a label in it, we store
;; it.
((and
(equal (org-element-type object) 'link)
(equal (org-element-property :type object) "file")
(org-file-image-p (org-element-property :path object)))
(if (org-element-property :name object)
(org-element-property :name object)
;; maybe we have a caption to get it from.
(let* ((parent (org-element-property :parent object)))
(when (and parent
(equal (org-element-type parent) 'paragraph))
(if (org-element-property :name parent)
;; caption paragraph may have a name which we use if it is there
(org-element-property :name parent)
;; else search caption
(let ((caption (s-join
""
(mapcar 'org-no-properties
(org-export-get-caption parent)))))
(when (string-match org-ref-label-re caption)
(match-string 1 caption))))))))
;; here on a paragraph (eg in a caption of an image). it is a paragraph with a caption
;; in a caption, with no name, but maybe a label
((equal (org-element-type object) 'paragraph)
(if (org-element-property :name object)
(org-element-property :name object)
;; See if it is in the caption name
(let ((caption (s-join "" (mapcar 'org-no-properties
(org-export-get-caption object)))))
(when (string-match org-ref-label-re caption)
(match-string 1 caption)))))
;; If you are in a table, we need to be at the beginning to
;; make sure we get the name. Note when in a caption it appears
;; you are in a table but org-at-table-p is nil there.
((or (equal (org-element-type object) 'table) (org-at-table-p))
(save-excursion
(goto-char (org-table-begin))
(let* ((table (org-element-context))
(label (org-element-property :name table))
(caption (s-join "" (mapcar 'org-no-properties
(org-export-get-caption table)))))
(when (null label)
;; maybe there is a label in the caption?
(when (string-match org-ref-label-link-re caption)
(match-string 1 caption))))))
;; and to #+namel: lines
((and (equal (org-element-type object) 'paragraph)
(org-element-property :name object))
(org-element-property :name object))
;; in a latex environment
((equal (org-element-type object) 'latex-environment)
(let ((value (org-element-property :value object))
label)
(when (string-match "\\\\label{\\(?1:[+a-zA-Z0-9:\\._-]*\\)}" value)
(match-string-no-properties 1 value))))
;; Match targets, like <<label>>
((equal (org-element-type object) 'target)
(org-element-property :value object))
(t
nil))))
(when label
(cl-loop for (reftype _) in org-ref-ref-types do
(org-link-store-props
:type reftype
:link (concat reftype ":" label)))
(format (concat org-ref-default-ref-type ":" label)))))
;; ** ref link
(org-link-set-parameters "ref"
:store #'org-ref-store-ref
:complete (apply-partially #'org-ref-complete-link "ref")
:activate-func #'org-ref-ref-activate
:follow #'org-ref-ref-jump-to
:export (apply-partially #'org-ref-ref-export "ref")
:face 'org-ref-ref-face
:help-echo #'org-ref-ref-help-echo)
;;** pageref link
(org-link-set-parameters "pageref"
:store #'org-ref-store-ref
:complete (apply-partially #'org-ref-complete-link "pageref")
:activate-func #'org-ref-ref-activate
:follow #'org-ref-ref-jump-to
:export (apply-partially #'org-ref-ref-export "pageref")
:face 'org-ref-ref-face
:complete (lambda (&optional arg) (org-ref-complete-link arg "pageref"))
:help-echo #'org-ref-ref-help-echo)
;;** nameref link
(org-link-set-parameters "nameref"
:store #'org-ref-store-ref
:complete (apply-partially #'org-ref-complete-link "nameref")
:activate-func #'org-ref-ref-activate
:follow #'org-ref-ref-jump-to
:export (apply-partially #'org-ref-ref-export "nameref")
:face 'org-ref-ref-face
:help-echo #'org-ref-ref-help-echo)
;;** eqref link
(org-link-set-parameters "eqref"
:store #'org-ref-store-ref
:complete (apply-partially #'org-ref-complete-link "eqref")
:activate-func #'org-ref-ref-activate
:follow #'org-ref-ref-jump-to
:export (apply-partially #'org-ref-ref-export "eqref")
:face 'org-ref-ref-face
:help-echo #'org-ref-ref-help-echo)
;;** autoref link
(org-link-set-parameters "autoref"
:store #'org-ref-store-ref
:complete (apply-partially #'org-ref-complete-link "autoref")
:activate-func #'org-ref-ref-activate
:follow #'org-ref-ref-jump-to
:export (apply-partially #'org-ref-ref-export "autoref")
:face 'org-ref-ref-face
:help-echo #'org-ref-ref-help-echo)
;;** cref link
;; for LaTeX cleveref package:
;; https://www.ctan.org/tex-archive/macros/latex/contrib/cleveref
(org-link-set-parameters "cref"
:store #'org-ref-store-ref
:complete (apply-partially #'org-ref-complete-link "cref")
:activate-func #'org-ref-ref-activate
:follow #'org-ref-ref-jump-to
:export (apply-partially #'org-ref-ref-export "cref")
:face 'org-ref-ref-face
:help-echo #'org-ref-ref-help-echo)
(org-link-set-parameters "Cref"
:store #'org-ref-store-ref
:complete (apply-partially #'org-ref-complete-link "Cref")
:activate-func #'org-ref-ref-activate
:follow #'org-ref-ref-jump-to
:export (apply-partially #'org-ref-ref-export "Cref")
:face 'org-ref-ref-face
:help-echo #'org-ref-ref-help-echo)
(defun org-ref-crefrange-export (path _desc backend)
(pcase backend
('latex
(let ((labels (split-string path ",")))
(format "\\crefrange{%s}{%s}" (cl-first labels) (cl-second labels))))))
(defun org-ref-Crefrange-export (path _desc backend)
(pcase backend
('latex
(let ((labels (split-string path ",")))
(format "\\crefrange{%s}{%s}" (cl-first labels) (cl-second labels))))))
(defun org-ref-crefrange-complete (cmd &optional _arg)
"Completing function for the c/Crefrange links."
(concat cmd ":"
(completing-read "Label 1: " (org-ref-get-labels))
","
(completing-read "Label 2: " (org-ref-get-labels))))
(org-link-set-parameters "crefrange"
:complete (apply-partially #'org-ref-crefrange-complete "crefrange")
:activate-func #'org-ref-ref-activate
:follow #'org-ref-ref-jump-to
:export #'org-ref-crefrange-export
:face 'org-ref-ref-face
:help-echo #'org-ref-ref-help-echo)
(org-link-set-parameters "Crefrange"
:complete (apply-partially #'org-ref-crefrange-complete "Crefrange")
:activate-func #'org-ref-ref-activate
:follow #'org-ref-ref-jump-to
:export #'org-ref-Crefrange-export
:face 'org-ref-ref-face
:help-echo #'org-ref-ref-help-echo)
;; * Insert link
(defvar org-ref-equation-environments
'("equation"
"equation*"
"align"
"align*"
"multline"
"multline*")
"LaTeX environments that should be treated as equations when referencing.")
(defvar org-ref-ref-type-inference-alist
'((org-ref-equation-label-p . "eqref"))
"Alist of predicate functions taking a label name and the
desired reference type if the predicate returns true.")
(defun org-ref-enclosing-environment (label)
"Returns the name of the innermost LaTeX environment containing
the first instance of the label, or nil of there is none."
(or
(save-excursion
(save-restriction
(widen)
(goto-char (point-min))
(let ((label-point (search-forward (format "\\label{%s}" label) nil t)))
(when label-point
(catch 'return
(let (last-begin-point last-env)
(while (setq
last-begin-point (re-search-backward "\\\\begin{\\([^}]+\\)}" nil t)
last-env (match-string-no-properties 1))
(let ((env-end-point
(search-forward (format "\\end{%s}" last-env) nil t)))
(if (and env-end-point
(> env-end-point label-point))
(throw 'return last-env)
(goto-char last-begin-point))))))))))
;; Check latex-environments for names, and matching environment
(org-element-map (org-element-parse-buffer) 'latex-environment
(lambda (le)
(when (and (string= label (org-element-property :name le))
(string-match
(concat "begin{\\("
(regexp-opt org-ref-equation-environments)
"\\)}")
(org-element-property :value le)))
(match-string 1 (org-element-property :value le))))
nil t)))
(defun org-ref-equation-label-p (label)
"Return non-nil if LABEL is an equation label."
(let ((maybe-env (org-ref-enclosing-environment label)))
(when maybe-env
(member maybe-env org-ref-equation-environments))))
(defun org-ref-infer-ref-type (label)
"Return inferred type for LABEL."
(or (cl-dolist (pred-pair org-ref-ref-type-inference-alist)
(when (funcall (car pred-pair) label)
(cl-return (eval (cdr pred-pair)))))
org-ref-default-ref-type))
(defun org-ref-ref-link-p ()
"Return the link at point if point is on a ref link."
(let ((el (org-element-context)))
(and (eq (org-element-type el) 'link)
(assoc (org-element-property :type el) org-ref-ref-types)
el)))
(defun org-ref-select-label ()
"Select a label in the buffer with annotated completion."
(let* ((type-annotation (lambda (s)
(let ((item (assoc s minibuffer-completion-table)))
(when item
(with-temp-buffer
(insert "\n" (cdr item))
(indent-rigidly (point-min) (point-max) 20)
(buffer-string))))))
(completion-extra-properties `(:annotation-function ,type-annotation)))
(completing-read "Label: " (org-ref-get-labels))))
(defun org-ref-insert-ref-link (&optional set-type)
"Insert a ref link.
If on a link, append a label to the end.
With a prefix arg SET-TYPE choose the ref type."
(interactive "P")
(let* ((minibuffer-setup-hook '(org-ref-minibuffer-prefix))
(label (org-ref-select-label))
(type (if (or set-type org-ref-prefix-arg)
(org-ref-select-ref-type)
;; in general, we prefer to infer the type, so that equations
;; get a better default. However, if you customize
;; `org-ref-default-ref-type', we use that instead. The most
;; common use case for this is setting that variable to cref,
;; which does its own automatic inference of the type.
(if (string= "ref" org-ref-default-ref-type)
(org-ref-infer-ref-type label)
org-ref-default-ref-type))))
(if-let* ((lnk (org-ref-ref-link-p))
(path (org-element-property :path lnk))
(beg (org-element-property :begin lnk))
(end (org-element-property :end lnk)))
(progn
(setf (plist-get (cadr lnk) :path) (concat path "," label))
(cl--set-buffer-substring beg end (org-element-interpret-data lnk)))
(insert (format "%s:%s" type label)))
(goto-char (org-element-property :end (org-element-context)))))
(provide 'org-ref-ref-links)
;;; org-ref-ref-links.el ends here

View File

@@ -0,0 +1,467 @@
;;; org-ref-refproc.el --- refproc - for exporting ref links in non-LaTeX backends -*- lexical-binding: t; -*-
;; For autoref and cref* links, a clever prefix is added at export.
;; Prefixes are found in `org-ref-refproc-clever-prefixes'
;; Use a keyword like this to set the style of clever prefixes. You can use a full or abbreviated prefix
;;
;; #+refproc: :abbreviate t :capitalize t
;;; Commentary:
;;
;;; Code:
(require 'org-ref-ref-links)
(defcustom org-ref-refproc-clever-prefixes
'((section :full "section" :abbrv "sec." :org-element headline)
(figure :full "figure" :abbrv "fig." :org-element link)
(table :full "table" :abbrv "tab." :org-element table)
(equation :full "equation" :abbrv "eq." :org-element latex-environment)
(proof :full "proof" :abbrv "pf." :org-element latex-environment)
(listing :full "listing" :abbrv "lst." :org-element src-block)
(lemma :full "lemma" :abbrv "lem." :org-element special-block)
(theorem :full "theorem" :abbrv "thm." :org-element special-block)
(corollary :full "corollary" :abbrv "cor." :org-element special-block))
"Prefixes for cleveref links.
plist with :full and :abbrv forms for each type.
:org-element is the element these are defined in."
:type 'sexp
:group 'org-ref)
;; * refproc
;;
(defun org-ref-refproc-get-options ()
"Return a plist of options from a #+refproc keyword.
Supported options are:
:abbreviate (nil or non-nil)
:capitalize (nil or non-nil)
These options only affect the cref* links."
(read (format "(%s)" (cadr (assoc "REFPROC"
(org-collect-keywords
'("REFPROC")))))))
(defun org-ref-get-ref-links ()
"Return a list of ref links in the buffer."
(org-element-map (org-element-parse-buffer) 'link
(lambda (lnk)
(when (assoc (org-element-property :type lnk) org-ref-ref-types)
lnk))))
(defun org-ref-refproc-referenceables ()
"Return a list of referenceable items, grouped by type.
This will be a list of (type label1 label2 ...).
Not all styles of target are currently supported. This supports
named tables, figures and src-blocks, headlines with a custom_id,
and latex_environments with a latex label or name (these are all
considered equations, which might be wrong for other
environments)."
(let* ((parse-data (org-element-parse-buffer))
type el
;; for each type, we specify what org-element to get the labels from.
(referencables (cl-loop for entry in org-ref-refproc-clever-prefixes
do
(setq type (car entry)
el (plist-get (cdr entry) :org-element))
collect
(cons type
(org-element-map parse-data el
(lambda (e)
(pcase el
;; Headlines
('headline
(cond
;; There is a custom_id, we use it.
((org-element-property :CUSTOM_ID e)
(org-element-property :CUSTOM_ID e))
;; See if there is a target in the heading
((string-match org-target-regexp
(org-element-property :raw-value e))
(match-string 1 (org-element-property :raw-value e)))
;; Check for a label link
((string-match (concat "label:" org-ref-label-re)
(org-element-property :raw-value e))
(match-string 1 (org-element-property :raw-value e)))))
;; Figures
('link
(cond
;; file link with a name property
((and (org-file-image-p (org-element-property :path e))
(org-element-property
:name (org-element-property :parent e)))
(org-element-property
:name (org-element-property :parent e)))
;; a label link in the caption
((and (org-file-image-p (org-element-property :path e))
(org-element-property
:caption (org-element-property :parent e))
(string-match (concat "label:" org-ref-label-re)
(org-element-interpret-data
(org-element-property
:caption
(org-element-property :parent e)))))
(match-string 1 (org-element-interpret-data
(org-element-property
:caption
(org-element-property :parent e)))))))
;; Tables
('table
(cond
;; A name keyword is preferred
((org-element-property :name e)
(org-element-property :name e))
;; a label link in a caption also works
((string-match (concat "label:" org-ref-label-re)
(or (org-element-interpret-data
(org-element-property :caption e))
""))
(match-string 1 (org-element-interpret-data
(org-element-property :caption e))))))
;; equations, proofs, and other latex environments
('latex-environment
(when (or (and (eq type 'equation)
(string-match "\\\\begin{equation}"
(org-element-property :value e)))
(and (eq type 'proof) (string-match "\\\\begin{proof}"
(org-element-property :value e))))
(cond
;; Name keyword
((org-element-property :name e)
(org-element-property :name e))
;; latex label in the value
((string-match "\\\\label{\\(.*\\)}" (org-element-property :value e))
(match-string 1 (org-element-property :value e))))))
;; special blocks
('special-block
(cond
((and (eq type 'lemma)
(org-element-property :name e)
(string= "lemma" (org-element-property :type e)))
(org-element-property :name e))
((and (eq type 'corollary)
(org-element-property :name e)
(string= "corollary" (org-element-property :type e)))
(org-element-property :name e))
((and (eq type 'theorem)
(org-element-property :name e)
(string= "theorem" (org-element-property :type e)))
(org-element-property :name e))))
;; Listings of code blocks
('src-block
(when-let (name (org-element-property :name e))
name)))))))))
referencables))
(defun org-ref-refproc-get-type (label referenceables)
"Get the type of reference LABEL refers to.
REFERENCEABLES comes from `org-ref-refproc-referenceables'.
Returns a plist (:type type :label label :index index)"
(cl-loop for type in referenceables
if (member label type)
return (list :type (car type) :label label :index (seq-position (cdr type) label 'equal))))
(defun org-ref-refproc-group-sort-labels (lbls referenceables)
"Group and sort the labels in LBLS.
REFERENCEABLES comes from `org-ref-refproc-referenceables'.
Returns a list of (list (type l1 i1) (type l2, i2)...) where l1
is label1, i1 is index1, etc.
This data structure has all the references from a single link
grouped by type. For some links there will only be one type, and
one label, because that is all that is allowed, e.g. for ref,
eqref, pageref, nameref and autoref.
For the cref* links though you can have many labels, even to
different kinds of things, and these are why we do the fancy
grouping and sorting here."
(cl-loop for entry in
(seq-group-by (lambda (el)
(plist-get el :type))
(cl-loop for label in lbls collect
(org-ref-refproc-get-type label referenceables)))
collect
(sort (cdr entry) (lambda (a b)
(< (plist-get a :index) (plist-get b :index))))))
;; * Refproc - a reference processor for org-mode
;;
;; The strategy is to compute string replacements that are just org-syntax, then
;; replace each link with the replacement.
(defun org-ref-refproc-replacement (ref-link referenceables backend)
"Compute a replacement for REF-LINK (an org-element).
REFERENCEABLES comes from `org-ref-refproc-referenceables'.
BACKEND is the export backend."
(let* ((ref-type (org-element-property :type ref-link))
(labels (split-string (org-element-property :path ref-link) ","))
(post-blanks (org-element-property :post-blank ref-link))
(data (cl-loop for label in labels collect (org-ref-refproc-get-type label referenceables))))
(pcase ref-type
;; These types only allow one label in the reference
("ref"
(when (> (length data) 1)
(error "A ref link can only have one label in it"))
(setq data (cl-first data))
(format "[[%s%s]]%s"
(if (eq 'section (plist-get data :type))
"#"
"")
(plist-get data :label)
;; add back post blank spaces.
(make-string post-blanks ? )))
("eqref"
(when (> (length data) 1)
(error "An eqref link can only have one label in it"))
(setq data (cl-first data))
(format (if (eq backend 'html)
"[[%s]]%s"
"([[%s]])%s")
(plist-get data :label)
;; add back post blank spaces.
(make-string post-blanks ? )))
;; This one doesn't make much sense in unpaginated exports, and I don't
;; have a way to get a page number anyway, so we make this a regular ref.
("pageref"
(when (> (length data) 1)
(error "A pageref link can only have one label in it"))
(setq data (cl-first data))
(format "[[%s%s]]%s"
(if (eq 'section (plist-get data :type))
"#"
"")
(plist-get data :label)
;; add back post blank spaces.
(make-string post-blanks ? )))
;; this will use the heading name, or caption of the ref
("nameref"
(when (> (length data) 1)
(error "A nameref link can only have one label in it"))
(setq data (cl-first data))
;; Basically I follow the link, and depending on the ref type get a
;; "name" for it. Right now there is no error if there is not a heading
;; or caption, you would just get an empty string.
(save-excursion
(goto-char (org-element-property :begin ref-link))
(search-forward ":")
(org-ref-ref-jump-to (org-element-property :path ref-link))
(pcase (plist-get data :type)
('section
(org-previous-visible-heading 1)
(format "[[#%s][%s]]%s"
(plist-get data :label)
(cl-fifth (org-heading-components))
(make-string post-blanks ? )))
('table
(format "[[%s][%s]]%s"
(plist-get data :label)
(org-element-interpret-data (org-element-property :caption (org-element-context)))
(make-string post-blanks ? )))
('figure
(format "[[%s][%s]]%s"
(plist-get data :label)
(org-element-interpret-data (org-element-property :caption (org-element-context)))
(make-string post-blanks ? )))
('listing
(format "[[%s][%s]]%s"
(plist-get data :label)
(org-element-interpret-data (org-element-property :caption (org-element-context)))
(make-string post-blanks ? )))
;; does equation even make sense? is there ever a caption?
(_
(error "The nameref link is not implemented for %S" data)))))
;; autoref is the first place we have to be clever.
("autoref"
(when (> (length data) 1)
(error "A pageref link can only have one label in it"))
(setq data (cl-first data))
(let* ((prefix-data (cdr (assoc (plist-get data :type) org-ref-refproc-clever-prefixes)))
(options (org-ref-refproc-get-options))
(prefix (plist-get prefix-data (if (plist-get options :abbreviate)
:abbrv
:full))))
(when (plist-get options :capitalize) (setq prefix (capitalize prefix)))
(format "%s [[%s%s]]%s"
prefix
(if (eq 'section (plist-get data :type))
"#"
"")
(plist-get data :label)
(make-string post-blanks ? ))))
;; Now we get to the cref* links. These are complicated, so I will pass
;; this out to dedicated functions. At this point, I have the ref-link,
("cref"
(org-ref-refproc-cref-replacement ref-link referenceables nil))
("Cref"
(org-ref-refproc-cref-replacement ref-link referenceables t))
(_
(error "%s links are not supported yet" ref-type)))))
(defun org-ref-refproc-cref-replacement (ref-link referenceables capitalize)
"Calculate a replacement for a REF-LINK.
REFERENCEABLES comes from `org-ref-refproc-referenceables'.
If CAPITALIZE is non-nil, capitalize the first entry (this is for
Cref) and is different than the capitalize option in #+refproc:
which capitalizes each prefix."
(let* ((options (org-ref-refproc-get-options))
;; I guess I know this will be cref or Cref here.
;; (ref-type (org-element-property :type ref-link))
(labels (split-string (org-element-property :path ref-link) ","))
(post-blanks (org-element-property :post-blank ref-link))
(data (cl-loop for label in labels collect (org-ref-refproc-get-type label referenceables)))
(groups (seq-group-by (lambda (entry)
(plist-get entry :type))
data))
;; this will be a list of sorted entries.
(sorted-groups (cl-loop for group in groups collect
(sort (cdr group) (lambda (a b)
(< (plist-get a :index) (plist-get b :index))))))
;; temp vars
prefix
prefix-data
;; Now we have to be clever on each sorted group. One day I should add compression to the groups, e.g. 1,2,3 - > 1 to 3
;; For each group we need a prefix, and it may have to be a plural prefix.
;; If there are two members of a group, they are joined by and
;; if there are more than two members of a group, they are separated by commas with and at the end.
(replacements (cl-loop for collection in sorted-groups collect
(pcase (length collection)
;; One thing in the list
(1
(setq collection (cl-first collection)
prefix-data (cdr (assoc (plist-get collection :type) org-ref-refproc-clever-prefixes))
prefix (plist-get prefix-data (if (plist-get options :abbreviate)
:abbrv
:full)))
(when (plist-get options :capitalize)
(setq prefix (capitalize prefix)))
(format "%s [[%s]]"
;; prefix
prefix
(concat
(if (eq 'section (plist-get collection :type)) "#" "")
(plist-get collection :label))))
(2
;; the prefix can be found from the first label, but we have to make it plural.
(setq prefix-data (cdr (assoc (plist-get (cl-first collection) :type)
org-ref-refproc-clever-prefixes))
prefix (plist-get prefix-data (if (plist-get options :abbreviate)
:abbrv
:full)))
(when (plist-get options :capitalize)
(setq prefix (capitalize prefix)))
;; Make it plural (substring "fig." -1)
(setq prefix (if (string= "." (substring prefix -1))
(concat (substring prefix 0 -1) "s.")
(concat prefix "s")))
(format "%s [[%s]] and [[%s]]"
prefix
(concat
(if (eq 'section (plist-get (cl-first collection) :type)) "#" "")
(plist-get (cl-first collection) :label))
(concat
(if (eq 'section (plist-get (cl-second collection) :type)) "#" "")
(plist-get (cl-second collection) :label))))
(_
;; the prefix can be found from the first label, but we have to make it plural.
(setq prefix-data (cdr (assoc (plist-get (cl-first collection) :type)
org-ref-refproc-clever-prefixes))
prefix (plist-get prefix-data (if (plist-get options :abbreviate)
:abbrv
:full)))
(when (plist-get options :capitalize)
(setq prefix (capitalize prefix)))
;; Make it plural. If the prefix ends in .
;; (i.e. it is abbreviated) we remove it and
;; add s.
(setq prefix (if (string= "." (substring prefix -1))
(concat (substring prefix 0 -1) "s.")
(concat prefix "s")))
;; now get
(format "%s %s and [[%s]]"
prefix
(string-join
(cl-loop for entry in (butlast collection) collect
(format "[[%s]]"
(concat
(if (eq 'section (plist-get entry :type)) "#" "")
(plist-get entry :label))))
", ")
;; the last one
(concat
(if (eq 'section (plist-get (car (last collection)) :type)) "#" "")
(plist-get (car (last collection)) :label))))))))
(when capitalize (setf (car replacements) (concat (capitalize (substring (car replacements) 0 1)) (substring (car replacements) 1))))
;; Finally, join them together with commas, and add post-blank spaces.
(concat
(pcase (length replacements)
(1
(cl-first replacements))
(2
(concat (cl-first replacements) " and " (cl-second replacements)))
(_
(concat (string-join (butlast replacements) ", ") " and " (car (last replacements)))))
(make-string post-blanks ? ))))
(defun org-ref-refproc (&optional backend)
"Process the buffer replacing all ref links with org syntax.
BACKEND is the
Meant to be used in an `org-export-before-parsing-hook' on a copy
of the buffer."
(let ((ref-links (org-ref-get-ref-links))
(referenceables (org-ref-refproc-referenceables)))
(cl-loop for ref in (reverse ref-links) do
(cl--set-buffer-substring (org-element-property :begin ref)
(org-element-property :end ref)
(org-ref-refproc-replacement ref referenceables backend)))))
(provide 'org-ref-refproc)
;;; org-ref-refproc.el ends here

View File

@@ -1,274 +0,0 @@
;;; org-ref-reftex.el --- org-ref completion setup with reftex -*- lexical-binding: t; -*-
;; Copyright (C) 2016 John Kitchin
;; Author: John Kitchin <jkitchin@andrew.cmu.edu>
;; Keywords:
;; 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 <http://www.gnu.org/licenses/>.
;;; Commentary: This is a bare-bones completion engine using only org-mode and
;;; vanilla Emacs functions. It is not being further developed.
;;
;;; Code:
(require 'reftex)
(require 'reftex-cite)
(require 'org-ref-utils)
(declare-function 'org-ref-find-bibliography "org-ref-core.el")
(declare-function 'org-ref-get-bibtex-key-and-file "org-ref-core.el")
(declare-function 'org-ref-bib-citation "org-ref-core.el")
(defvar org-ref-cite-types)
(defvar org-ref-open-notes-function)
(defvar org-ref-get-pdf-filename-function)
(defvar org-ref-open-pdf-function)
;;;###autoload
(defun org-ref-reftex-completion ()
"Use reftex and org-mode for completion."
(interactive)
;; Define core functions for org-ref
(setq org-ref-insert-link-function 'org-ref-insert-cite-link
org-ref-insert-cite-function 'org-ref-insert-cite-link
org-ref-insert-label-function 'org-insert-link
org-ref-insert-ref-function 'org-insert-link
org-ref-cite-onclick-function 'org-ref-cite-onclick-minibuffer-menu)
(message "reftex completion in org-ref loaded."))
(org-ref-reftex-completion)
(define-key org-mode-map
(kbd org-ref-insert-cite-key)
org-ref-insert-link-function)
;; Messages in the minbuffer conflict with the minibuffer menu. So we turn them
;; off.
(setq org-ref-show-citation-on-enter nil)
;;* org-mode / reftex setup
(defun org-mode-reftex-setup ()
"Setup `org-mode' and reftex for `org-ref'."
(and (buffer-file-name)
(file-exists-p (buffer-file-name))
(global-auto-revert-mode t))
(make-local-variable 'reftex-cite-format)
(setq reftex-cite-format 'org))
(add-hook 'org-mode-hook 'org-mode-reftex-setup)
(eval-after-load 'reftex-vars
'(progn
(add-to-list 'reftex-cite-format-builtin
'(org "Org-mode citation"
((?\C-m . "cite:%l") ; default
(?d . ",%l") ; for appending
(?a . "autocite:%l")
(?t . "citet:%l")
(?T . "citet*:%l")
(?p . "citep:%l")
(?P . "citep*:%l")
(?h . "citeauthor:%l")
(?H . "citeauthor*:%l")
(?y . "citeyear:%l")
(?x . "citetext:%l")
(?n . "nocite:%l"))))))
(defun org-ref-insert-cite-link (alternative-cite)
"Insert a default citation link using reftex.
If you are on a link, it appends to the end of the link,
otherwise, a new link is inserted. Use a prefix
arg (ALTERNATIVE-CITE) to get a menu of citation types."
(interactive "P")
(org-ref-find-bibliography)
(let* ((object (org-element-context))
(link-string-end (org-element-property :end object)))
(if (not alternative-cite)
(cond
;; case where we are in a link
((and (equal (org-element-type object) 'link)
(-contains? org-ref-cite-types
(org-element-property :type object)))
(goto-char link-string-end)
;; sometimes there are spaces at the end of the link
;; this code moves point pack until no spaces are there
(skip-chars-backward " ")
(insert (concat "," (mapconcat
'identity
(reftex-citation t ?a) ","))))
;; We are next to a link, and we want to append
((save-excursion
(backward-char)
(and (equal (org-element-type (org-element-context)) 'link)
(-contains? org-ref-cite-types
(org-element-property
:type (org-element-context)))))
(skip-chars-backward " ")
(insert (concat "," (mapconcat
'identity
(reftex-citation t ?a) ","))))
;; insert fresh link
(t
(insert
(concat org-ref-default-citation-link
":"
(mapconcat 'identity (reftex-citation t) ",")))))
;; you pressed a C-u so we run this code
(reftex-citation))))
;;;###autoload
(defun org-ref-open-notes-from-reftex ()
"Call reftex, and open notes for selected entry."
(interactive)
;; now look for entry in the notes file
(if org-ref-bibliography-notes
(find-file-other-window org-ref-bibliography-notes)
(error "org-ref-bibliography-notes is not set to anything"))
(org-open-link-from-string
(format "[[#%s]]" (car (reftex-citation t))))
(funcall org-ref-open-notes-function))
(defalias 'ornr 'org-ref-open-notes-from-reftex)
;;*** Minibuffer menu
;;;###autoload
(defun org-ref-cite-onclick-minibuffer-menu (&optional _link-string)
"Action when a cite link is clicked on.
Provides a menu of context sensitive actions. If the bibtex entry
has a pdf, you get an option to open it. If there is a doi, you
get a lot of options. LINK-STRING is used by the link function."
(interactive)
(let* ((results (org-ref-get-bibtex-key-and-file))
(key (car results))
(pdf-file (funcall org-ref-get-pdf-filename-function key))
(bibfile (cdr results))
(url (save-excursion
(with-temp-buffer
(insert-file-contents bibfile)
(bibtex-set-dialect (parsebib-find-bibtex-dialect) t)
(bibtex-search-entry key)
(bibtex-autokey-get-field "url"))))
(doi (save-excursion
(with-temp-buffer
(insert-file-contents bibfile)
(bibtex-set-dialect (parsebib-find-bibtex-dialect) t)
(bibtex-search-entry key)
;; I like this better than bibtex-url which does not always find
;; the urls
(bibtex-autokey-get-field "doi")))))
(when (string= "" doi) (setq doi nil))
(when (string= "" url) (setq url nil))
(setq org-ref-cite-menu-funcs '())
;; open action
(when
bibfile
(add-to-list
'org-ref-cite-menu-funcs
'("o" "pen" org-ref-open-citation-at-point)))
;; pdf
(when (file-exists-p pdf-file)
(add-to-list
'org-ref-cite-menu-funcs
`("p" "df" ,org-ref-open-pdf-function) t))
;; notes
(add-to-list
'org-ref-cite-menu-funcs
'("n" "otes" org-ref-open-notes-at-point) t)
;; url
(when (or url doi)
(add-to-list
'org-ref-cite-menu-funcs
'("u" "rl" org-ref-open-url-at-point) t))
;; doi funcs
(when doi
(add-to-list
'org-ref-cite-menu-funcs
'("w" "os" org-ref-wos-at-point) t)
(add-to-list
'org-ref-cite-menu-funcs
'("c" "iting" org-ref-wos-citing-at-point) t)
(add-to-list
'org-ref-cite-menu-funcs
'("r" "elated" org-ref-wos-related-at-point) t)
(add-to-list
'org-ref-cite-menu-funcs
'("g" "oogle scholar" org-ref-google-scholar-at-point) t)
(add-to-list
'org-ref-cite-menu-funcs
'("P" "ubmed" org-ref-pubmed-at-point) t))
;; add user functions
(dolist (tup org-ref-user-cite-menu-funcs)
(add-to-list
'org-ref-cite-menu-funcs
tup t))
;; finally quit
(add-to-list
'org-ref-cite-menu-funcs
'("q" "uit" (lambda ())) t)
;; now we make a menu
;; construct menu string as a message
(message
(concat
(let* ((results (org-ref-get-bibtex-key-and-file))
(key (car results))
(bibfile (cdr results)))
(save-excursion
(with-temp-buffer
(insert-file-contents bibfile)
(bibtex-set-dialect (parsebib-find-bibtex-dialect) t)
(bibtex-search-entry key)
(org-ref-bib-citation))))
"\n"
(mapconcat
(lambda (tup)
(concat "[" (elt tup 0) "]"
(elt tup 1) " "))
org-ref-cite-menu-funcs "")))
;; get the input
(let* ((input (read-char-exclusive))
(choice (assoc
(char-to-string input) org-ref-cite-menu-funcs)))
;; now run the function (2nd element in choice)
(when choice
(funcall
(elt
choice
2))))))
(provide 'org-ref-reftex)
;;; org-ref-reftex.el ends here

View File

@@ -29,26 +29,26 @@
(require 'org)
(require 'org-ref-utils)
(org-ref-link-set-parameters "orcid"
:follow (lambda
(link-string)
(browse-url
(format "http://orcid.org/%s" link-string)))
:export (lambda (keyword desc format)
(cond
((eq format 'html)
(format "<a href=\"http://orcid.org/%s\">orcid:%s</a>" keyword (or desc keyword))))))
(org-link-set-parameters "orcid"
:follow (lambda
(link-string)
(browse-url
(format "http://orcid.org/%s" link-string)))
:export (lambda (keyword desc format)
(cond
((eq format 'html)
(format "<a href=\"http://orcid.org/%s\">orcid:%s</a>" keyword (or desc keyword))))))
(org-ref-link-set-parameters "researcherid"
:follow (lambda
(link-string)
(browse-url
(format "http://www.researcherid.com/rid/%s" link-string)))
:export (lambda (keyword desc format)
(cond
((eq format 'html)
(format "<a href=\"http://www.researcherid.com/rid/%s\">ResearcherID:%s</a>"
keyword (or desc keyword))))))
(org-link-set-parameters "researcherid"
:follow (lambda
(link-string)
(browse-url
(format "http://www.researcherid.com/rid/%s" link-string)))
:export (lambda (keyword desc format)
(cond
((eq format 'html)
(format "<a href=\"http://www.researcherid.com/rid/%s\">ResearcherID:%s</a>"
keyword (or desc keyword))))))
(provide 'org-ref-sci-id)
;;; org-ref-sci-id.el ends here

View File

@@ -159,63 +159,63 @@ Requires `*scopus-api-key*' to be defined."
"Citing articles"))
(org-ref-link-set-parameters "eid"
:follow (lambda (eid)
"Opens the hydra menu."
(setq *hydra-eid* eid)
(scopus-hydra/body))
:export (lambda (keyword desc format)
(cond
((eq format 'html)
(format "<a href=\" http://www.scopus.com/record/display.url?eid=%s&origin=resultslist\">%s</a>" keyword (or desc keyword)))
((eq format 'latex)
(format "\\href{http://www.scopus.com/record/display.url?eid=%s&origin=resultslist}{%s}"
keyword (or desc keyword))))))
(org-link-set-parameters "eid"
:follow (lambda (eid)
"Opens the hydra menu."
(setq *hydra-eid* eid)
(scopus-hydra/body))
:export (lambda (keyword desc format)
(cond
((eq format 'html)
(format "<a href=\" http://www.scopus.com/record/display.url?eid=%s&origin=resultslist\">%s</a>" keyword (or desc keyword)))
((eq format 'latex)
(format "\\href{http://www.scopus.com/record/display.url?eid=%s&origin=resultslist}{%s}"
keyword (or desc keyword))))))
(org-ref-link-set-parameters "scopus-search"
:follow (lambda (query)
(scopus-basic-search query))
:export (lambda (query desc format)
(let ((url (format
"http://www.scopus.com/results/results.url?sort=plf-f&src=s&sot=b&sdt=b&sl=%s&s=TITLE-ABS-KEY%%28%s%%29&origin=searchbasic"
(length (url-unhex-string (concat "TITLE-ABS-KEY%28" (url-hexify-string query) "%29")))
(url-hexify-string query))))
(cond
((eq format 'html)
(format "<a href=\"%s\">%s</a>" url (or desc query)))
((eq format 'latex)
(format "\\href{%s}{%s}" url (or desc query)))))))
(org-link-set-parameters "scopus-search"
:follow (lambda (query)
(scopus-basic-search query))
:export (lambda (query desc format)
(let ((url (format
"http://www.scopus.com/results/results.url?sort=plf-f&src=s&sot=b&sdt=b&sl=%s&s=TITLE-ABS-KEY%%28%s%%29&origin=searchbasic"
(length (url-unhex-string (concat "TITLE-ABS-KEY%28" (url-hexify-string query) "%29")))
(url-hexify-string query))))
(cond
((eq format 'html)
(format "<a href=\"%s\">%s</a>" url (or desc query)))
((eq format 'latex)
(format "\\href{%s}{%s}" url (or desc query)))))))
(org-ref-link-set-parameters "scopus-advanced-search"
:follow (lambda (query)
(scopus-advanced-search query))
:export (lambda (query desc format)
(let ((url (format
"http://www.scopus.com/results/results.url?sort=plf-f&src=s&sot=a&sdt=a&sl=%s&s=%s&origin=searchadvanced"
(length (url-hexify-string query))
(url-hexify-string query))))
(cond
((eq format 'html)
(format "<a href=\"%s\">%s</a>" url (or desc query)))
((eq format 'latex)
(format "\\href{%s}{%s}" url (or desc query)))))))
(org-link-set-parameters "scopus-advanced-search"
:follow (lambda (query)
(scopus-advanced-search query))
:export (lambda (query desc format)
(let ((url (format
"http://www.scopus.com/results/results.url?sort=plf-f&src=s&sot=a&sdt=a&sl=%s&s=%s&origin=searchadvanced"
(length (url-hexify-string query))
(url-hexify-string query))))
(cond
((eq format 'html)
(format "<a href=\"%s\">%s</a>" url (or desc query)))
((eq format 'latex)
(format "\\href{%s}{%s}" url (or desc query)))))))
(org-ref-link-set-parameters "scopusid"
:follow (lambda
(link-string)
(browse-url
(format
"http://www.scopus.com/authid/detail.url?origin=AuthorProfile&authorId=%s"
link-string)))
:export (lambda (keyword desc format)
(cond
((eq format 'latex)
(format "\\href{http://www.scopus.com/authid/detail.url?origin=AuthorProfile&authorId=%s}{%s}"
keyword (or desc (concat "scopusid:" keyword))))
((eq format 'html)
(format "<a href=\"http://www.scopus.com/authid/detail.url?origin=AuthorProfile&authorId=%s\">%s</a>"
keyword (or desc (concat "scopusid:" keyword)))))))
(org-link-set-parameters "scopusid"
:follow (lambda
(link-string)
(browse-url
(format
"http://www.scopus.com/authid/detail.url?origin=AuthorProfile&authorId=%s"
link-string)))
:export (lambda (keyword desc format)
(cond
((eq format 'latex)
(format "\\href{http://www.scopus.com/authid/detail.url?origin=AuthorProfile&authorId=%s}{%s}"
keyword (or desc (concat "scopusid:" keyword))))
((eq format 'html)
(format "<a href=\"http://www.scopus.com/authid/detail.url?origin=AuthorProfile&authorId=%s\">%s</a>"
keyword (or desc (concat "scopusid:" keyword)))))))
(provide 'org-ref-scopus)

View File

@@ -1,6 +1,6 @@
;;; org-ref-url-utils.el --- Utility functions to scrape DOIs from urls -*- lexical-binding: t; -*-
;; Copyright (C) 2015 John Kitchin
;; Copyright (C) 2015-2021 John Kitchin
;; Author: John Kitchin <jkitchin@andrew.cmu.edu>
;; Keywords:
@@ -21,10 +21,13 @@
;;; Commentary:
;; Drag a webpage onto a bibtex file to insert a bibtex entry.
;;
;; [2021-08-29 Sun] I have not found drag-and-drop reliable or convenient. I
;; don't recommend using this, but I am also not deleting it (yet).
;; This works by scraping DOIs from the content at the URL using patterns in
;; `org-ref-doi-regexps'. If one DOI is found, it is added as an entry. If
;; multiple DOIs are found, you will get a helm selection buffer to choose what
;; multiple DOIs are found, you will get a selection buffer to choose what
;; you want to add. You can add new patterns to `org-ref-doi-regexps'.
;; You can press Control to "debug" a URL, which will open a buffer of the
@@ -38,16 +41,14 @@
;;; Code:
(defvar org-ref-bibliography-entry-format)
(defvar org-ref-get-pdf-filename-function)
(defvar org-ref-notes-function)
(defvar org-ref-cite-types)
(defvar org-cliplink-escape-alist)
(declare-function 'org-ref-get-bibtex-key-and-file "org-ref-core.el")
(declare-function 'org-ref-find-bibliography "org-ref-core.el")
(declare-function 'org-ref-key-in-file-p "org-ref-core.el")
(declare-function 'org-ref-bib-citation "org-ref-core.el")
(declare-function 'org-ref-get-bibtex-key-under-cursor "org-ref-core.el")
(declare-function dnd-handle-one-url "dnd")
(declare-function dnd--unescape-uri "dnd")
(require 'doi-utils)
(require 'f)
@@ -56,14 +57,6 @@
(require 'cl-lib))
;; See https://github.com/jkitchin/org-ref/issues/812
;; apparently there is a function name change coming in
;; (if (and (not (fboundp 'dnd-unescape-uri))
;; (fboundp 'dnd--escape-uri))
;; (defalias 'dnd-unescape-uri 'dnd--unescape-uri)
;; (warn "dnd-unescape-uri is undefined. Some things may not work."))
(defgroup org-ref-url nil
"Customization group for org-ref-url-utils"
:tag "Org Ref URL"
@@ -87,18 +80,22 @@ the DOI."
:type '(repeat regexp)
:group 'org-ref-url-utils)
(defvar org-ref-url-title-re
"<title.?+?>\\([[:ascii:][:nonascii:]]*?\\|.+\\)</title>"
"Regular expression for matching title.")
(defvar org-ref-url-author-re
"<meta name=\"author\" content=\"\\(.+\\)\"\s?/?>"
"Regular expression for matching author.")
(defvar org-ref-url-date-re
"<[a-z].+ class=\\(.?+date.[^>]*\\)>\\([[:ascii:][:nonascii:]]*?\\)</[a-z].+>"
"Regular expression for matching date.")
(defvar org-ref-url-bibtex-template
"@misc{key,
title = {${:title}},
@@ -128,30 +125,17 @@ Returns a list of collected DOIs in the order found."
(let ((dois '()))
(with-current-buffer (url-retrieve-synchronously url)
(cl-loop for doi-pattern in org-ref-doi-regexps
do
(goto-char (point-min))
(while (re-search-forward doi-pattern nil t)
(cl-pushnew (match-string 1) dois :test #'equal)))
do
(goto-char (point-min))
(while (re-search-forward doi-pattern nil t)
(cl-pushnew (match-string 1) dois :test #'equal)))
(reverse dois))))
(defun org-ref-url-add-doi-entries (_)
"Add all entries for CANDIDATE in `helm-marked-candidates'.
This is used in a helm selection command in `org-ref-url-dnd-protocol'."
(cl-loop for doi in (helm-marked-candidates)
do
(doi-utils-add-bibtex-entry-from-doi
doi
(buffer-file-name))
;; this removes two blank lines before each entry.
(bibtex-beginning-of-entry)
(delete-char -2)))
(defun org-ref-url-dnd-protocol (url action)
"Protocol function for use in `dnd-protocol-alist'.
We scrape DOIs from the url first. If there is one, we add it. If
there is more than one, we offer a helm buffer of selections. If
there is more than one, we offer a completion buffer of selections. If
no DOI is found, we create a misc entry, with a prompt for a key."
;; make sure we are on a bib-file
(if (and (buffer-file-name)
@@ -166,40 +150,11 @@ no DOI is found, we create a misc entry, with a prompt for a key."
action)
;; Multiple DOIs found
((> (length dois) 1)
(helm :sources
`((name . "Select a DOI")
(candidates . ,(let ((dois '()))
(with-current-buffer (url-retrieve-synchronously url)
(cl-loop for doi-pattern in org-ref-doi-regexps
do
(goto-char (point-min))
(while (re-search-forward doi-pattern nil t)
(cl-pushnew
;; Cut off the doi, sometimes
;; false matches are long.
(cons (format "%40s | %s"
(substring
(match-string 1)
0 (min
(length (match-string 1))
40))
doi-pattern)
(match-string 1))
dois
:test #'equal)))
(reverse dois))))
(action . org-ref-url-add-doi-entries)))
action)
(let ((doi (completing-read "Select a DOI: " dois)))
(doi-utils-add-bibtex-entry-from-doi doi (buffer-file-name))))
;; No DOIs found, add a misc entry.
(t
(goto-char (point-max))
(insert (format "\n@misc{,
url = {%s},
note = {Last accessed %s}
}"
url
(current-time-string)))
(bibtex-clean-entry)
(org-ref-url-html-to-bibtex (buffer-file-name) url)
action)))
;; pass back to dnd. Copied from `org-download-dnd'. Apparently
;; returning nil does not do this.
@@ -218,7 +173,7 @@ no DOI is found, we create a misc entry, with a prompt for a key."
A doi will be either doi:10.xxx or 10.xxx."
(if (and (buffer-file-name)
(f-ext? (buffer-file-name) "bib"))
(let ((doi (dnd-unescape-uri doi)))
(let ((doi (dnd--unescape-uri doi)))
;; Get the actual doi now
(string-match "\\(?:DOI\\|doi\\)?:? *\\(10.*\\)" doi)
(setq doi (match-string 1 doi))
@@ -237,89 +192,21 @@ A doi will be either doi:10.xxx or 10.xxx."
(add-to-list 'dnd-protocol-alist '("^10" . org-ref-doi-dnd-protocol))
;;* Debug URL in a buffer with C-dnd
;;* Debugging DOIs from a URL
;; You can use this to see if there are any DOIs in a URL, and to use re-builder
;; to add new patterns to `org-ref-doi-regexps'.
;;;###autoload
(defun org-ref-url-debug-url (url)
"Open a buffer to URL with all doi patterns highlighted."
(interactive)
(interactive "sURL: ")
(switch-to-buffer
(url-retrieve-synchronously url))
(highlight-regexp
(mapconcat 'identity org-ref-doi-regexps "\\|")))
;;;###autoload
(defun org-ref-url-dnd-debug (event)
"Drag-n-drop function to debug a url."
(interactive "e")
(org-ref-url-debug-url (cadr (car (last event)))))
(define-key bibtex-mode-map (kbd "<C-drag-n-drop>") 'org-ref-url-dnd-debug)
;;* Add all DOI bibtex entries with M-dnd
(defun org-ref-url-add-all-doi-entries (url)
"Add all DOI bibtex entries for URL."
(cl-loop for doi in (org-ref-url-scrape-dois url)
do
(ignore-errors
(doi-utils-add-bibtex-entry-from-doi
doi
(buffer-file-name))
;; this removes two blank lines before each entry.
(bibtex-beginning-of-entry)
(delete-char -2))))
;;;###autoload
(defun org-ref-url-dnd-all (event)
"Drag-n-drop function to get all DOI bibtex entries for a url.
You probably do not want to do this since the DOI patterns are
not perfect, and some hits are not actually DOIs."
(interactive "e")
(org-ref-url-add-all-doi-entries (cadr (car (last event)))))
(define-key bibtex-mode-map (kbd "<M-drag-n-drop>") 'org-ref-url-dnd-all)
;; Get first DOI if there is one with s-dnd
(defun org-ref-url-add-first-doi-entry (url)
"Add first DOI bibtex entry for URL if there is one."
(let* ((dois (org-ref-url-scrape-dois url))
(doi (car dois)))
(if doi
(progn
(doi-utils-add-bibtex-entry-from-doi
doi
(buffer-file-name))
;; this removes two blank lines before each entry.
(bibtex-beginning-of-entry)
(delete-char -2))
;; no doi, add misc
(goto-char (point-max))
(insert (format "\n@misc{,
url = {%s},
note = {Last accessed %s}
}"
url
(current-time-string)))
(bibtex-clean-entry))))
;;;###autoload
(defun org-ref-url-dnd-first (event)
"Drag-n-drop function to download the first DOI in a url."
(interactive "e")
(org-ref-url-add-first-doi-entry (cadr (car (last event)))))
(define-key bibtex-mode-map (kbd "<s-drag-n-drop>") 'org-ref-url-dnd-first)
;; HTML to BibTeX functions
;;* HTML to BibTeX functions
(defun org-ref-url-html-replace (string)
"Replace HTML entities in STRING with their unicode equivalent."
@@ -364,8 +251,10 @@ Fields include author, title, url, urldate, and year."
;; find author
(goto-char (point-min))
(when (re-search-forward org-ref-url-author-re nil t)
(push (cons :author (match-string 1)) fields))
(let ((author (if (re-search-forward org-ref-url-author-re nil t)
(match-string 1)
"Unknown")))
(push (cons :author author) fields))
;; find title
(goto-char (point-min))

File diff suppressed because it is too large Load Diff

View File

@@ -28,31 +28,31 @@
(require 'org-ref-utils)
;;; Code:
(org-ref-link-set-parameters "wos"
:follow (lambda (accession-number)
(browse-url
(concat
"http://ws.isiknowledge.com/cps/openurl/service?url_ver=Z39.88-2004&rft_id=info:ut/"
accession-number)))
:export (lambda (accession-number desc format)
(cond
((eq format 'html)
(format "<a href=\"http://ws.isiknowledge.com/cps/openurl/service?url_ver=Z39.88-2004&rft_id=info:ut/%s\">%s</a>"
accession-number
(or desc (concat "wos:" accession-number)))))))
(org-link-set-parameters "wos"
:follow (lambda (accession-number)
(browse-url
(concat
"http://ws.isiknowledge.com/cps/openurl/service?url_ver=Z39.88-2004&rft_id=info:ut/"
accession-number)))
:export (lambda (accession-number desc format)
(cond
((eq format 'html)
(format "<a href=\"http://ws.isiknowledge.com/cps/openurl/service?url_ver=Z39.88-2004&rft_id=info:ut/%s\">%s</a>"
accession-number
(or desc (concat "wos:" accession-number)))))))
(org-ref-link-set-parameters "wos-search"
:follow (lambda (path)
(browse-url
(format "http://gateway.webofknowledge.com/gateway/Gateway.cgi?topic=%s&GWVersion=2&SrcApp=WEB&SrcAuth=HSB&DestApp=UA&DestLinkType=GeneralSearchSummary"
(s-join "+" (split-string path)))))
:export (lambda (link desc format)
(cond
((eq format 'html)
(format "<a href=\"%s\">%s</a>"
(format "http://gateway.webofknowledge.com/gateway/Gateway.cgi?topic=%s&GWVersion=2&SrcApp=WEB&SrcAuth=HSB&DestApp=UA&DestLinkType=GeneralSearchSummary"
(s-join "+" (split-string link)))
(or desc link))))))
(org-link-set-parameters "wos-search"
:follow (lambda (path)
(browse-url
(format "http://gateway.webofknowledge.com/gateway/Gateway.cgi?topic=%s&GWVersion=2&SrcApp=WEB&SrcAuth=HSB&DestApp=UA&DestLinkType=GeneralSearchSummary"
(s-join "+" (split-string path)))))
:export (lambda (link desc format)
(cond
((eq format 'html)
(format "<a href=\"%s\">%s</a>"
(format "http://gateway.webofknowledge.com/gateway/Gateway.cgi?topic=%s&GWVersion=2&SrcApp=WEB&SrcAuth=HSB&DestApp=UA&DestLinkType=GeneralSearchSummary"
(s-join "+" (split-string link)))
(or desc link))))))
;;;###autoload
(defun wos-search ()

View File

@@ -235,7 +235,8 @@
eprint = { http://dx.doi.org/10.1021/acscatal.5b00538 },
}
@online{jkitchin76:online,
@misc{jkitchin76:online,
author = {John Kitchin},
title = {jkitchin/org-ref: org-mode modules for citations,
cross-references, bibliographies in org-mode and useful bibtex
tools to go with it.},
@@ -290,7 +291,7 @@
@article{xu-2017-first-princ,
author = {Xu, Zhongnan and Salvador, Paul A. and Kitchin, John R.},
title = {First-Principles Investigation of the Epitaxial Stabilization
of Oxide Polymorphs: \ce{TiO2} on \ce{(Sr,Ba)TiO3}},
of Oxide Polymorphs: \ce{TiO2} on \ce{(Sr{,}Ba)TiO3}},
journal = {ACS Applied Materials \& Interfaces},
volume = {9},
number = {4},

View File

@@ -1,12 +1,12 @@
;;; org-ref.el --- citations, cross-references and bibliographies in org-mode
;;; org-ref.el --- citations, cross-references and bibliographies in org-mode -*- lexical-binding: t; -*-
;; Copyright(C) 2014-2016 John Kitchin
;; Copyright(C) 2014-2021 John Kitchin
;; Author: John Kitchin <jkitchin@andrew.cmu.edu>
;; URL: https://github.com/jkitchin/org-ref
;; Version: 1.1.1
;; Version: 3.0
;; Keywords: org-mode, cite, ref, label
;; Package-Requires: ((dash "2.11.0") (htmlize "1.51") (helm "1.5.5") (helm-bibtex "2.0.0") (ivy "0.8.0") (hydra "0.13.2") (key-chord "0") (s "1.10.0") (f "0.18.0") (pdf-tools "0.7"))
;; Package-Requires: ((dash "0") (s "0") (f "0") (htmlize "0") (hydra "0") (avy "0") (parsebib "0") (bibtex-completion "0") (citeproc "0"))
;; This file is not currently part of GNU Emacs.
;; This program is free software; you can redistribute it and/or
@@ -26,18 +26,26 @@
;;; Commentary:
;;
;; Lisp code to setup bibliography, cite, ref and label org-mode links.
;; Also sets up reftex and helm for org-mode citations. The links are
;; clickable and do things that are useful.
;; Lisp code to setup bibliography, cite, ref and label org-mode links. The
;; links are clickable and do things that are useful.
;;
;; The default setup uses helm-bibtex.
;; This uses vanilla completing-read in Emacs. You can customize by requiring
;; `org-ref-helm' or `org-ref-ivy' after this.
;; You should really read org-ref.org in this package for details.
;;
;;; Code:
(require 'org-ref-core)
(require org-ref-completion-library)
(setq org-ref-insert-link-function 'org-ref-insert-link
org-ref-insert-cite-function 'org-ref-insert-cite-link
org-ref-insert-label-function 'org-ref-insert-label-link
org-ref-insert-ref-function 'org-ref-insert-ref-link
org-ref-cite-onclick-function (lambda (_) (org-ref-citation-hydra/body)))
;;* The end
(provide 'org-ref)

File diff suppressed because it is too large Load Diff

View File

@@ -14,6 +14,8 @@
;; This code is mostly wrappers around the command line utilities at
;; http://sourceforge.net/p/bibutils/home/Bibutils.
;;
;; on a Mac: brew install bibutils
;; Here are the commands that are available.