├── .ert-runner ├── .gitignore ├── test ├── biblatex_csl │ ├── video.txt │ ├── 179-escaped_curly_brackets.txt │ ├── periodical.txt │ ├── 95-non-standard_biblatex_date_fields.txt │ ├── book-title-maintitle-series.txt │ ├── 75-extended_biblatex_name_spec.txt │ ├── 65-map_type_to_genre.txt │ ├── britannica.txt │ ├── 143-capitalize_subtitles_starting_with_quote.txt │ ├── corporate_author.txt │ ├── kant-ku.txt │ ├── ctan.txt │ ├── basic.txt │ ├── averroes-bland.txt │ ├── manual.txt │ ├── thesis.txt │ ├── online.txt │ ├── article.txt │ ├── inproceedings.txt │ ├── inspect.org │ ├── incollection.txt │ ├── inbook.txt │ ├── report.txt │ └── patent.txt ├── citeproc-test-int-humans.el ├── citeproc-test-csl-suite.el ├── human │ ├── extlink_DOI.txt │ ├── extlink_URLOrgNoLinkIfTargetEqualsAnchor.txt │ ├── extlink_PMID.txt │ ├── extlink_PMCID.txt │ ├── extlink_TitleFallback.txt │ ├── extlink_URL.txt │ ├── extlink_TitleFallbackDOIPriority.txt │ ├── extlink_LinkImmediateURLPrefix.txt │ ├── extlink_DontLinkNonimmediateURLPrefix.txt │ ├── textcase_StopWordBeforeHyphen.txt │ ├── citation_YearOnly.txt │ ├── citation_AuthorOnly.txt │ ├── citation_TextualDontApplyForNumericOrLabel.txt │ ├── citation_LocatorOnly.txt │ ├── citation_Textual.txt │ ├── citation_SuppressAuthor.txt │ ├── citation_TextualCapitalizeFirst.txt │ ├── intlink_NonNoteStyle.txt │ ├── intlink_NoteStyle.txt │ ├── citation_ApplyModeAfterSortingCites.txt │ ├── citation_IgnoreEtAl.txt │ └── citation_TextualGroupedCites.txt ├── citeproc-test-int-formatters.el ├── etc │ └── subbibs.json ├── citeproc-test-int-subbibs.el ├── citeproc-test-int-biblatex.el └── expected_fails.lst ├── Cask ├── Makefile ├── .github └── workflows │ └── ci.yml ├── citeproc-macro.el ├── citeproc-subbibs.el ├── citeproc-locale.el ├── citeproc-itemdata.el ├── citeproc-term.el ├── citeproc-choose.el ├── citeproc-prange.el ├── citeproc-lib.el ├── citeproc-number.el ├── citeproc-generic-elements.el ├── citeproc-itemgetters.el ├── citeproc-sort.el ├── citeproc-test-human.el ├── citeproc-proc.el ├── citeproc-disamb.el └── citeproc-s.el /.ert-runner: -------------------------------------------------------------------------------- 1 | -L ./ 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled 2 | *.elc 3 | 4 | # Packaging 5 | .cask 6 | 7 | # Backup files 8 | *~ 9 | 10 | # Undo-tree save-files 11 | *.~undo-tree 12 | 13 | # CSL suite 14 | test/locales 15 | test/suite 16 | dist 17 | -------------------------------------------------------------------------------- /test/biblatex_csl/video.txt: -------------------------------------------------------------------------------- 1 | --- 2 | @video{x1,title={Blah}} 3 | @movie{x2,title={Blah}} 4 | --- 5 | - blt-type: video 6 | id: x1 7 | title: Blah 8 | type: motion_picture 9 | - blt-type: movie 10 | id: x2 11 | title: Blah 12 | type: motion_picture 13 | -------------------------------------------------------------------------------- /Cask: -------------------------------------------------------------------------------- 1 | (source gnu) 2 | (source melpa) 3 | (source org) 4 | 5 | (package-file "citeproc.el") 6 | 7 | (files "*.el") 8 | 9 | (development 10 | (depends-on "ert-runner") 11 | (depends-on "org-plus-contrib") 12 | (depends-on "yaml") 13 | (depends-on "parsebib") 14 | (depends-on "ht")) 15 | -------------------------------------------------------------------------------- /test/citeproc-test-int-humans.el: -------------------------------------------------------------------------------- 1 | ;;; citeproc-test-int-humans.el --- internal tests in CSL humanly readable format 2 | 3 | (require 'citeproc-test-human) 4 | 5 | (citeproc-test-human-create-from-dir "./test/human") 6 | 7 | (provide 'citeproc-test-int-humans) 8 | 9 | ;;; citeproc-test-int-humans.el ends here 10 | -------------------------------------------------------------------------------- /test/citeproc-test-csl-suite.el: -------------------------------------------------------------------------------- 1 | ;;; citeproc-test-csl-suite.el --- CSL tests from the official suite 2 | 3 | (require 'citeproc-test-human) 4 | 5 | (citeproc-test-human-create-from-dir 6 | "./test/suite/processor-tests/humans" "./test/expected_fails.lst" "suite") 7 | 8 | (provide 'citeproc-test-csl-suite) 9 | 10 | ;;; citeproc-test-csl-suite.el ends here 11 | -------------------------------------------------------------------------------- /test/biblatex_csl/179-escaped_curly_brackets.txt: -------------------------------------------------------------------------------- 1 | --- 2 | @software{expressionTest, 3 | author = {Myself, Me}, 4 | title = {Regex:[01]\{20\}}, 5 | year = {2025} 6 | } 7 | --- 8 | - author: 9 | - family: Myself 10 | given: Me 11 | blt-type: software 12 | id: expressionTest 13 | issued: 2025 14 | title: Regex:[01]{20} 15 | type: software 16 | 17 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CASK ?= cask 2 | CASK_EXEC ?= ${CASK} exec 3 | 4 | all: update clean compile csl_suite 5 | 6 | update: 7 | $(CASK) update 8 | 9 | compile: 10 | $(CASK) build 11 | 12 | test_csl_suite: 13 | ${CASK_EXEC} ert-runner test/citeproc-test-csl-suite.el 14 | 15 | test_internals: 16 | ${CASK_EXEC} ert-runner test/citeproc-test-int*.el 17 | 18 | test: 19 | ${CASK_EXEC} ert-runner test/*.el 20 | 21 | clean: 22 | rm -f *.elc 23 | 24 | .PHONY: all clean test 25 | -------------------------------------------------------------------------------- /test/biblatex_csl/periodical.txt: -------------------------------------------------------------------------------- 1 | --- 2 | @periodical{jcg, 3 | Annotation = {This is a periodical entry with an issn field.}, 4 | Issn = {0097-8493}, 5 | Issuetitle = {Semantic {3D} media and content}, 6 | Number = 4, 7 | Title = {Computers and Graphics}, 8 | Volume = 35, 9 | Year = 2011} 10 | --- 11 | - annote: This is a periodical entry with an issn field. 12 | blt-type: periodical 13 | container-title: Computers and graphics 14 | id: jcg 15 | ISSN: 0097-8493 16 | issue: 4 17 | issued: 2011 18 | title: Semantic 3D media and content 19 | type: article-journal 20 | volume: 35 21 | -------------------------------------------------------------------------------- /test/biblatex_csl/95-non-standard_biblatex_date_fields.txt: -------------------------------------------------------------------------------- 1 | --- 2 | @article{article-req, 3 | Author = {Author, Ann}, 4 | Date = {2013-01}, 5 | Urldate = {2021-12-12T19:00:12}, 6 | Journaltitle = {The Journaltitle}, 7 | Title = {An article entry with just the required fields}, 8 | Langid = {english}} 9 | --- 10 | - accessed: 2021-12-12 11 | author: 12 | - family: Author 13 | given: Ann 14 | 15 | blt-type: article 16 | container-title: The journaltitle 17 | id: article-req 18 | issued: 2013-01 19 | language: en-US 20 | title: An article entry with just the required fields 21 | type: article-journal 22 | -------------------------------------------------------------------------------- /test/human/extlink_DOI.txt: -------------------------------------------------------------------------------- 1 | >>===== OUTPUT-FORMAT =====>> 2 | org 3 | <<===== OUTPUT-FORMAT =====<< 4 | 5 | 6 | >>===== MODE =====>> 7 | bibliography 8 | <<===== MODE =====<< 9 | 10 | 11 | >>===== RESULT =====>> 12 | [[https://doi.org/10.1000/xyz123][10.1000/xyz123]] 13 | <<===== RESULT =====<< 14 | 15 | 16 | >>===== CSL =====>> 17 | 24 | <<===== CSL =====<< 25 | 26 | 27 | >>===== INPUT =====>> 28 | [ 29 | { 30 | "id": "ITEM-1", 31 | "DOI": "10.1000/xyz123" 32 | } 33 | ] 34 | <<===== INPUT =====<< 35 | -------------------------------------------------------------------------------- /test/human/extlink_URLOrgNoLinkIfTargetEqualsAnchor.txt: -------------------------------------------------------------------------------- 1 | >>===== OUTPUT-FORMAT =====>> 2 | org 3 | <<===== OUTPUT-FORMAT =====<< 4 | 5 | 6 | >>===== MODE =====>> 7 | bibliography 8 | <<===== MODE =====<< 9 | 10 | 11 | >>===== RESULT =====>> 12 | http://orgmode.org 13 | <<===== RESULT =====<< 14 | 15 | 16 | >>===== CSL =====>> 17 | 24 | <<===== CSL =====<< 25 | 26 | 27 | >>===== INPUT =====>> 28 | [ 29 | { 30 | "id": "ITEM-1", 31 | "URL": "http://orgmode.org" 32 | } 33 | ] 34 | <<===== INPUT =====<< 35 | -------------------------------------------------------------------------------- /test/human/extlink_PMID.txt: -------------------------------------------------------------------------------- 1 | >>===== OUTPUT-FORMAT =====>> 2 | org 3 | <<===== OUTPUT-FORMAT =====<< 4 | 5 | 6 | >>===== MODE =====>> 7 | bibliography 8 | <<===== MODE =====<< 9 | 10 | 11 | >>===== RESULT =====>> 12 | [[https://www.ncbi.nlm.nih.gov/pubmed/25166873][25166873]] 13 | <<===== RESULT =====<< 14 | 15 | 16 | >>===== CSL =====>> 17 | 24 | <<===== CSL =====<< 25 | 26 | 27 | >>===== INPUT =====>> 28 | [ 29 | { 30 | "id": "ITEM-1", 31 | "PMID": "25166873", 32 | "PMCID": "PMC3531190" 33 | } 34 | ] 35 | <<===== INPUT =====<< 36 | -------------------------------------------------------------------------------- /test/human/extlink_PMCID.txt: -------------------------------------------------------------------------------- 1 | >>===== OUTPUT-FORMAT =====>> 2 | org 3 | <<===== OUTPUT-FORMAT =====<< 4 | 5 | 6 | >>===== MODE =====>> 7 | bibliography 8 | <<===== MODE =====<< 9 | 10 | 11 | >>===== RESULT =====>> 12 | [[https://www.ncbi.nlm.nih.gov/pmc/articles/PMC3531190][PMC3531190]] 13 | <<===== RESULT =====<< 14 | 15 | 16 | >>===== CSL =====>> 17 | 24 | <<===== CSL =====<< 25 | 26 | 27 | >>===== INPUT =====>> 28 | [ 29 | { 30 | "id": "ITEM-1", 31 | "PMID": "25166873", 32 | "PMCID": "PMC3531190" 33 | } 34 | ] 35 | <<===== INPUT =====<< 36 | -------------------------------------------------------------------------------- /test/human/extlink_TitleFallback.txt: -------------------------------------------------------------------------------- 1 | >>===== OUTPUT-FORMAT =====>> 2 | org 3 | <<===== OUTPUT-FORMAT =====<< 4 | 5 | 6 | >>===== MODE =====>> 7 | bibliography 8 | <<===== MODE =====<< 9 | 10 | 11 | >>===== RESULT =====>> 12 | [[http://orgmode.org][Org mode is great]] 13 | <<===== RESULT =====<< 14 | 15 | 16 | >>===== CSL =====>> 17 | 24 | <<===== CSL =====<< 25 | 26 | 27 | >>===== INPUT =====>> 28 | [ 29 | { 30 | "id": "ITEM-1", 31 | "title": "Org mode is great", 32 | "URL": "http://orgmode.org" 33 | } 34 | ] 35 | <<===== INPUT =====<< 36 | -------------------------------------------------------------------------------- /test/human/extlink_URL.txt: -------------------------------------------------------------------------------- 1 | >>===== OUTPUT-FORMAT =====>> 2 | html 3 | <<===== OUTPUT-FORMAT =====<< 4 | 5 | 6 | >>===== MODE =====>> 7 | bibliography 8 | <<===== MODE =====<< 9 | 10 | 11 | >>===== RESULT =====>> 12 |
13 |
http://orgmode.org
14 |
15 | <<===== RESULT =====<< 16 | 17 | 18 | >>===== CSL =====>> 19 | 26 | <<===== CSL =====<< 27 | 28 | 29 | >>===== INPUT =====>> 30 | [ 31 | { 32 | "id": "ITEM-1", 33 | "URL": "http://orgmode.org" 34 | } 35 | ] 36 | <<===== INPUT =====<< 37 | -------------------------------------------------------------------------------- /test/human/extlink_TitleFallbackDOIPriority.txt: -------------------------------------------------------------------------------- 1 | >>===== OUTPUT-FORMAT =====>> 2 | org 3 | <<===== OUTPUT-FORMAT =====<< 4 | 5 | 6 | >>===== MODE =====>> 7 | bibliography 8 | <<===== MODE =====<< 9 | 10 | 11 | >>===== RESULT =====>> 12 | [[https://doi.org/10.1000/xyz123][Org mode is great]] 13 | <<===== RESULT =====<< 14 | 15 | 16 | >>===== CSL =====>> 17 | 24 | <<===== CSL =====<< 25 | 26 | 27 | >>===== INPUT =====>> 28 | [ 29 | { 30 | "id": "ITEM-1", 31 | "title": "Org mode is great", 32 | "URL": "http://orgmode.org", 33 | "DOI": "10.1000/xyz123" 34 | } 35 | ] 36 | <<===== INPUT =====<< 37 | -------------------------------------------------------------------------------- /test/human/extlink_LinkImmediateURLPrefix.txt: -------------------------------------------------------------------------------- 1 | >>===== OUTPUT-FORMAT =====>> 2 | latex 3 | <<===== OUTPUT-FORMAT =====<< 4 | 5 | 6 | >>===== MODE =====>> 7 | bibliography 8 | <<===== MODE =====<< 9 | 10 | 11 | >>===== RESULT =====>> 12 | A title. \url{https://doi.org/10.1000/xyz123}\bigskip 13 | <<===== RESULT =====<< 14 | 15 | 16 | >>===== CSL =====>> 17 | 25 | <<===== CSL =====<< 26 | 27 | 28 | >>===== INPUT =====>> 29 | [ 30 | { 31 | "id": "ITEM-1", 32 | "DOI": "10.1000/xyz123", 33 | "title": "A title" 34 | } 35 | ] 36 | <<===== INPUT =====<< 37 | -------------------------------------------------------------------------------- /test/biblatex_csl/book-title-maintitle-series.txt: -------------------------------------------------------------------------------- 1 | --- 2 | @book{item1, 3 | Author = {Author, Al}, 4 | Date = {2013}, 5 | Location = {Location}, 6 | Mainsubtitle = {Mainsubtitle}, 7 | Maintitle = {Maintitle}, 8 | Maintitleaddon = {Maintitleaddon}, 9 | Number = {3}, 10 | Publisher = {Publisher}, 11 | Series = {Series}, 12 | Subtitle = {Subtitle}, 13 | Title = {Title of the book}, 14 | Titleaddon = {Titleaddon}, 15 | } 16 | --- 17 | - author: 18 | - family: Author 19 | given: Al 20 | blt-type: book 21 | collection-number: 3 22 | collection-title: Series 23 | id: item1 24 | issued: 2013 25 | publisher: Publisher 26 | publisher-place: Location 27 | title: "Maintitle: Mainsubtitle. Maintitleaddon" 28 | type: book 29 | volume-title: "Title of the book: Subtitle. Titleaddon" 30 | -------------------------------------------------------------------------------- /test/biblatex_csl/75-extended_biblatex_name_spec.txt: -------------------------------------------------------------------------------- 1 | --- 2 | @book{goethe2005, 3 | langid = {german}, 4 | location = {{Frankfurt am Main}}, 5 | title = {Not A Real Book}, 6 | date = {2005}, 7 | author = {family=Goethe, given=Johann Wolfgang, prefix=von, useprefix=false and given=Antonie, prefix=van, family=Leeuwenhoek, useprefix=true}, 8 | editor = {Schöne, Albrecht}} 9 | --- 10 | - author: 11 | - dropping-particle: von 12 | family: Goethe 13 | given: Johann Wolfgang 14 | - family: Leeuwenhoek 15 | given: Antonie 16 | non-dropping-particle: van 17 | blt-type: book 18 | editor: 19 | - family: Schöne 20 | given: Albrecht 21 | id: goethe2005 22 | issued: 2005 23 | language: de-DE 24 | publisher-place: Frankfurt am Main 25 | title: Not A Real Book 26 | type: book 27 | -------------------------------------------------------------------------------- /test/human/extlink_DontLinkNonimmediateURLPrefix.txt: -------------------------------------------------------------------------------- 1 | >>===== OUTPUT-FORMAT =====>> 2 | latex 3 | <<===== OUTPUT-FORMAT =====<< 4 | 5 | 6 | >>===== MODE =====>> 7 | bibliography 8 | <<===== MODE =====<< 9 | 10 | 11 | >>===== RESULT =====>> 12 | A title. https://doi.org/ \href{https://doi.org/10.1000/xyz123}{10.1000/xyz123}\bigskip 13 | <<===== RESULT =====<< 14 | 15 | 16 | >>===== CSL =====>> 17 | 25 | <<===== CSL =====<< 26 | 27 | 28 | >>===== INPUT =====>> 29 | [ 30 | { 31 | "id": "ITEM-1", 32 | "DOI": "10.1000/xyz123", 33 | "title": "A title" 34 | } 35 | ] 36 | <<===== INPUT =====<< 37 | -------------------------------------------------------------------------------- /test/biblatex_csl/65-map_type_to_genre.txt: -------------------------------------------------------------------------------- 1 | --- 2 | @Jurisdiction{bgh2013usedsoft-ii, 3 | author = {BGH}, 4 | type = {Urteil}, 5 | number = {I ZR 129/08}, 6 | eventdate = {2013-07-17}, 7 | shortjournal = {GRUR}, 8 | journaltitle = {Gewerblicher Rechtsschutz und Urheberrecht}, 9 | year = {2014}, 10 | pages = {264-272}, 11 | title = {UsedSoft II}, 12 | commentator = {Malte Stieper}, 13 | langid = {german} 14 | } 15 | --- 16 | - author: 17 | - family: BGH 18 | blt-type: jurisdiction 19 | container-title: Gewerblicher Rechtsschutz und Urheberrecht 20 | container-title-short: GRUR 21 | event-date: 2013-07-17 22 | genre: Urteil 23 | id: bgh2013usedsoft-ii 24 | issued: 2014 25 | language: de-DE 26 | number: I ZR 129/08 27 | page: 264-272 28 | title: UsedSoft II 29 | type: legal_case 30 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [ push, pull_request, workflow_dispatch ] 4 | 5 | 6 | jobs: 7 | test: 8 | runs-on: ubuntu-latest 9 | strategy: 10 | matrix: 11 | emacs_version: 12 | # - 26.3 13 | - 28.1 14 | - 29.1 15 | - 30.1 16 | steps: 17 | - uses: purcell/setup-emacs@master 18 | with: 19 | version: ${{ matrix.emacs_version }} 20 | - uses: conao3/setup-cask@master 21 | - uses: actions/checkout@v2 22 | - name: Test 23 | env: 24 | COVERALLS_FLAG_NAME: Emacs ${{ matrix.emacs_version }} 25 | run: | 26 | git clone --depth 1 https://github.com/citation-style-language/test-suite.git test/suite 27 | git clone --depth 1 https://github.com/citation-style-language/locales.git test/locales 28 | cask install 29 | cask build 30 | make test 31 | -------------------------------------------------------------------------------- /test/biblatex_csl/britannica.txt: -------------------------------------------------------------------------------- 1 | --- 2 | @Collection{britannica, 3 | editor = {Preece, Warren E.}, 4 | title = {The New Encyclop{\ae}dia {Britannica}}, 5 | date = 2003, 6 | edition = 15, 7 | volumes = 32, 8 | publisher = {Encyclop{\ae}dia Britannica}, 9 | location = {Chicago, Ill.}, 10 | label = {EB}, 11 | sorttitle = {Encyclop{\ae}dia Britannica}, 12 | indextitle = {Encyclop{\ae}dia Britannica, The New}, 13 | shorttitle = {Encyclop{\ae}dia {Britannica}} 14 | } 15 | --- 16 | - blt-type: collection 17 | citation-label: EB 18 | edition: 15 19 | editor: 20 | - family: Preece 21 | given: Warren E. 22 | id: britannica 23 | issued: 2003 24 | number-of-volumes: 32 25 | publisher: Encyclopædia Britannica 26 | publisher-place: Chicago, Ill. 27 | title: The new encyclopædia Britannica 28 | title-short: Encyclopædia Britannica 29 | type: book 30 | -------------------------------------------------------------------------------- /test/biblatex_csl/143-capitalize_subtitles_starting_with_quote.txt: -------------------------------------------------------------------------------- 1 | --- 2 | @Article{myers-1988, 3 | author = {Myers, Norman}, 4 | title = {Threatened biotas}, 5 | journal = {Environmentalist}, 6 | year = 1988, 7 | volume = 8, 8 | number = 3, 9 | pages = {187-208}, 10 | month = {Sep}, 11 | type = {Abstract}, 12 | subtitle = {"Hot spots" in tropical forests}, 13 | day = 01, 14 | issn = {1573-2991}, 15 | doi = {10.1007/BF02240252} 16 | } 17 | --- 18 | - DOI: 10.1007/BF02240252 19 | ISSN: 1573-2991 20 | author: 21 | - family: Myers 22 | given: Norman 23 | blt-type: article 24 | container-title: Environmentalist 25 | genre: Abstract 26 | id: myers-1988 27 | issue: 3 28 | issued: 1988-09 29 | page: 187-208 30 | title: "Threatened biotas: \"Hot spots\" in tropical forests" 31 | title-short: "Threatened biotas" 32 | type: article-journal 33 | volume: 8 34 | -------------------------------------------------------------------------------- /test/human/textcase_StopWordBeforeHyphen.txt: -------------------------------------------------------------------------------- 1 | >>==== MODE ====>> 2 | citation 3 | <<==== MODE ====<< 4 | 5 | >>==== RESULT ====>> 6 | Employee pro-Environmental Behavior 7 | <<==== RESULT ====<< 8 | 9 | >>==== CITATION-ITEMS ====>> 10 | [ 11 | [ 12 | { 13 | "id": "ITEM-1" 14 | } 15 | ] 16 | ] 17 | <<==== CITATION-ITEMS ====<< 18 | 19 | >>==== CSL ====>> 20 | 35 | <<==== CSL ====<< 36 | 37 | >>==== INPUT ====>> 38 | [ 39 | { 40 | "container-title": "Employee pro-environmental behavior", 41 | "id": "ITEM-1", 42 | "type": "book" 43 | } 44 | ] 45 | <<==== INPUT ====<< 46 | 47 | -------------------------------------------------------------------------------- /test/biblatex_csl/corporate_author.txt: -------------------------------------------------------------------------------- 1 | --- 2 | @legislation{bt12-4022, 3 | author = {{Deutscher Bundestag}}, 4 | title = {Entwurf eines Zweiten Gesetzes zur Änderung des Urheberrechtsgesetzes}, 5 | langid = {german}, 6 | date = {1992-12-18}} 7 | 8 | @book{CUDA, 9 | author = {{NVIDIA Corporation}}, 10 | title = {{NVIDIA CUDA} Compute Unified Device Architecture Programming Guide}, 11 | publisher = {NVIDIA Corporation}, 12 | year = {2007}} 13 | 14 | @book{corp, 15 | author = {{Big corporation} and Smith, John}, 16 | title = {A book by a corporation and an actual person}, 17 | year = {1998}} 18 | --- 19 | - author: 20 | - literal: Deutscher Bundestag 21 | blt-type: legislation 22 | issued: 1992-12-18 23 | id: "bt12-4022" 24 | language: de-DE 25 | title: Entwurf eines Zweiten Gesetzes zur Änderung des Urheberrechtsgesetzes 26 | type: bill 27 | - author: 28 | - literal: NVIDIA Corporation 29 | blt-type: book 30 | id: "CUDA" 31 | issued: 2007 32 | publisher: NVIDIA Corporation 33 | title: NVIDIA CUDA compute unified device architecture programming guide 34 | type: book 35 | - author: 36 | - literal: Big corporation 37 | - family: Smith 38 | given: John 39 | blt-type: book 40 | id: "corp" 41 | issued: 1998 42 | title: A book by a corporation and an actual person 43 | type: book 44 | -------------------------------------------------------------------------------- /test/biblatex_csl/kant-ku.txt: -------------------------------------------------------------------------------- 1 | An edition of Kant's Collected Works, volume five. This is 2 | an inbook entry which explicitly refers to the Critique of 3 | Judgment only, not to the entire fifth volume. 4 | --- 5 | @InBook{kant:ku, 6 | title = {Kritik der Urtheilskraft}, 7 | date = {1968}, 8 | author = {Kant, Immanuel}, 9 | booktitle = {Kritik der praktischen Vernunft. Kritik der Urtheilskraft}, 10 | bookauthor = {Kant, Immanuel}, 11 | maintitle = {Kants Werke. Akademie Textausgabe}, 12 | volume = {V}, 13 | publisher = {Walter de Gruyter}, 14 | location = {Berlin}, 15 | pages = {165-485}, 16 | shorthand = {KU}, 17 | langid = {german}, 18 | annotation = {An edition of Kant's Collected Works, volume five.}} 19 | --- 20 | - annote: An edition of Kant's Collected Works, volume five. 21 | author: 22 | - given: Immanuel 23 | family: Kant 24 | blt-type: inbook 25 | container-author: 26 | - given: Immanuel 27 | family: Kant 28 | container-title: Kants Werke. Akademie Textausgabe 29 | id: kant:ku 30 | issued: 1968 31 | language: de-DE 32 | page: 165-485 33 | publisher: Walter de Gruyter 34 | publisher-place: Berlin 35 | title: Kritik der Urtheilskraft 36 | type: chapter 37 | volume: V 38 | volume-title: Kritik der praktischen Vernunft. Kritik der 39 | Urtheilskraft 40 | -------------------------------------------------------------------------------- /test/biblatex_csl/ctan.txt: -------------------------------------------------------------------------------- 1 | --- 2 | @Online{ctan, 3 | title = {{CTAN}}, 4 | date = 2006, 5 | url = {http://www.ctan.org}, 6 | subtitle = {{The Comprehensive TeX Archive Network}}, 7 | urldate = {2006-10-01}, 8 | label = {CTAN}, 9 | annotation = {This is an online entry. The \textsc{url}, which is 10 | given in the url field, is transformed into a 11 | clickable link if hyperref support has been 12 | enabled. Note the format of the urldate field 13 | (yyyy-mm-dd) in the database file. Also note the 14 | label field which may be used as a fallback by 15 | citation styles which need an author and/or a 16 | year}} 17 | --- 18 | - blt-type: online 19 | URL: "http://www.ctan.org" 20 | accessed: 2006-10-01 21 | annote: This is an online entry. The url, which is given 22 | in the url field, is transformed into a clickable link if hyperref 23 | support has been enabled. Note the format of the urldate field 24 | (yyyy-mm-dd) in the database file. Also note the label field which 25 | may be used as a fallback by citation styles which need an author 26 | and/or a year 27 | citation-label: CTAN 28 | id: ctan 29 | issued: 2006 30 | title: "CTAN: The Comprehensive TeX Archive Network" 31 | title-short: CTAN 32 | type: webpage 33 | 34 | -------------------------------------------------------------------------------- /test/biblatex_csl/basic.txt: -------------------------------------------------------------------------------- 1 | --- 2 | @Book{item1, 3 | author="John Doe", 4 | title="First Book", 5 | year="2005", 6 | address="Cambridge", 7 | publisher="Cambridge University Press" 8 | } 9 | 10 | @Article{item2, 11 | author="John Doe", 12 | title="Article", 13 | year="2006", 14 | journal="Journal of Generic Studies", 15 | volume="6", 16 | pages="33-34" 17 | } 18 | 19 | @InCollection{пункт3, 20 | author="John Doe and Jenny Roe", 21 | title="Why Water Is Wet", 22 | booktitle="Third Book", 23 | editor="Sam Smith", 24 | publisher="Oxford University Press", 25 | address="Oxford", 26 | year="2007" 27 | } 28 | --- 29 | - author: 30 | - family: Doe 31 | given: John 32 | blt-type: book 33 | id: item1 34 | issued: 2005 35 | publisher: Cambridge University Press 36 | publisher-place: Cambridge 37 | title: First book 38 | type: book 39 | - author: 40 | - family: Doe 41 | given: John 42 | blt-type: article 43 | container-title: Journal of generic studies 44 | id: item2 45 | issued: 2006 46 | page: 33-34 47 | title: Article 48 | type: article-journal 49 | volume: 6 50 | - author: 51 | - family: Doe 52 | given: John 53 | - family: Roe 54 | given: Jenny 55 | blt-type: incollection 56 | container-title: Third book 57 | editor: 58 | - family: Smith 59 | given: Sam 60 | id: пункт3 61 | issued: 2007 62 | publisher: Oxford University Press 63 | publisher-place: Oxford 64 | title: Why water is wet 65 | type: chapter 66 | -------------------------------------------------------------------------------- /test/biblatex_csl/averroes-bland.txt: -------------------------------------------------------------------------------- 1 | --- 2 | @Book{averroes-bland, 3 | author = {Averroes}, 4 | title = {The Epistle on the Possibility of Conjunction with the Active 5 | Intellect by {Ibn Rushd} with the Commentary of {Moses Narboni}}, 6 | date = 1982, 7 | editor = {Bland, Kalman P.}, 8 | translator = {Bland, Kalman P.}, 9 | series = {Moreshet: {Studies} in {Jewish} History, Literature and Thought}, 10 | number = 7, 11 | publisher = {Jewish Theological Seminary of America}, 12 | location = {New York}, 13 | keywords = {primary}, 14 | indextitle = {Epistle on the Possibility of Conjunction, The}, 15 | shorttitle = {Possibility of Conjunction}, 16 | annotation = {A book entry with a series and a 17 | number. Note the concatenation of the editor 18 | and translator fields as well as the 19 | indextitle field}, 20 | langid = {english} 21 | } 22 | --- 23 | - annote: A book entry with a series and a number. Note the 24 | concatenation of the editor and translator fields as well as the 25 | indextitle field 26 | author: 27 | - family: Averroes 28 | blt-type: book 29 | collection-number: 7 30 | collection-title: "Moreshet: Studies in Jewish history, literature and thought" 31 | editor: 32 | - family: Bland 33 | given: Kalman P. 34 | id: averroes-bland 35 | issued: 1982 36 | keyword: primary 37 | language: en-US 38 | publisher: Jewish Theological Seminary of America 39 | publisher-place: New York 40 | title: The epistle on the possibility of conjunction with the active 41 | intellect by Ibn Rushd with the commentary of Moses Narboni 42 | title-short: Possibility of conjunction 43 | translator: 44 | - family: Bland 45 | given: Kalman P. 46 | type: book 47 | -------------------------------------------------------------------------------- /test/biblatex_csl/manual.txt: -------------------------------------------------------------------------------- 1 | --- 2 | @Manual{cms, 3 | title = {The {Chicago} Manual of Style}, 4 | date = 2003, 5 | subtitle = {The Essential Guide for Writers, Editors, and Publishers}, 6 | edition = 15, 7 | publisher = {University of Chicago Press}, 8 | location = {Chicago, Ill.}, 9 | isbn = {0-226-10403-6}, 10 | label = {CMS}, 11 | sorttitle = {Chicago Manual of Style}, 12 | indextitle = {Chicago Manual of Style, The}, 13 | shorttitle = {Chicago Manual of Style}, 14 | annotation = {This is a manual entry without an author or 15 | editor. Note the label field in the database 16 | file which is provided for author-year citation styles. Also 17 | note the sorttitle and indextitle fields. By 18 | default, all entries without an author or 19 | editor are alphabetized by title but we want 20 | this entry to be alphabetized under C rather than 21 | T. There's also an isbn field}, 22 | } 23 | --- 24 | - annote: This is a manual entry without an author or editor. Note the 25 | label field in the database file which is provided for author-year 26 | citation styles. Also note the sorttitle and indextitle fields. By 27 | default, all entries without an author or editor are alphabetized by 28 | title but we want this entry to be alphabetized under C rather 29 | than T. There's also an isbn field 30 | blt-type: manual 31 | citation-label: CMS 32 | edition: 15 33 | id: cms 34 | ISBN: 0-226-10403-6 35 | issued: 2003 36 | publisher: University of Chicago Press 37 | publisher-place: Chicago, Ill. 38 | title: "The Chicago manual of style: The essential guide for writers, 39 | editors, and publishers" 40 | title-short: Chicago manual of style 41 | type: book 42 | -------------------------------------------------------------------------------- /test/human/citation_YearOnly.txt: -------------------------------------------------------------------------------- 1 | >>===== MODE =====>> 2 | citation 3 | <<===== MODE =====<< 4 | 5 | 6 | >>===== RESULT =====>> 7 | (1986) 8 | <<===== RESULT =====<< 9 | 10 | 11 | >>===== CITATIONS =====>> 12 | [ 13 | [ 14 | { 15 | "citationID": "CITATION-1", 16 | "citationItems": [ 17 | { 18 | "id": "ITEM-1" 19 | } 20 | ], 21 | "properties": { 22 | "noteIndex": 0, 23 | "mode": "year-only" 24 | } 25 | }, 26 | [], 27 | [] 28 | ] 29 | 30 | ] 31 | <<===== CITATIONS =====<< 32 | 33 | 34 | 35 | >>===== CSL =====>> 36 | 65 | <<===== CSL =====<< 66 | 67 | 68 | >>===== INPUT =====>> 69 | [ 70 | { 71 | "author": [ 72 | { 73 | "family": "Smith", 74 | "given": "John" 75 | } 76 | ], 77 | "issued": { 78 | "date-parts": [ 79 | [ 80 | 1986 81 | ] 82 | ] 83 | }, 84 | "type": "book", 85 | "id": "ITEM-1" 86 | } 87 | ] 88 | <<===== INPUT =====<< 89 | -------------------------------------------------------------------------------- /test/human/citation_AuthorOnly.txt: -------------------------------------------------------------------------------- 1 | >>===== MODE =====>> 2 | citation 3 | <<===== MODE =====<< 4 | 5 | 6 | >>===== RESULT =====>> 7 | (Smith) 8 | <<===== RESULT =====<< 9 | 10 | 11 | >>===== CITATIONS =====>> 12 | [ 13 | [ 14 | { 15 | "citationID": "CITATION-1", 16 | "citationItems": [ 17 | { 18 | "id": "ITEM-1" 19 | } 20 | ], 21 | "properties": { 22 | "noteIndex": 0, 23 | "mode": "author-only" 24 | } 25 | }, 26 | [], 27 | [] 28 | ] 29 | 30 | ] 31 | <<===== CITATIONS =====<< 32 | 33 | 34 | 35 | >>===== CSL =====>> 36 | 66 | <<===== CSL =====<< 67 | 68 | 69 | >>===== INPUT =====>> 70 | [ 71 | { 72 | "author": [ 73 | { 74 | "family": "Smith", 75 | "given": "John" 76 | } 77 | ], 78 | "title": "A nice title", 79 | "issued": { 80 | "date-parts": [ 81 | [ 82 | 1986 83 | ] 84 | ] 85 | }, 86 | "type": "book", 87 | "id": "ITEM-1" 88 | } 89 | ] 90 | <<===== INPUT =====<< 91 | -------------------------------------------------------------------------------- /test/human/citation_TextualDontApplyForNumericOrLabel.txt: -------------------------------------------------------------------------------- 1 | >>===== MODE =====>> 2 | citation 3 | <<===== MODE =====<< 4 | 5 | 6 | >>===== RESULT =====>> 7 | [1] 8 | [1] 9 | <<===== RESULT =====<< 10 | 11 | 12 | >>===== CITATIONS =====>> 13 | [ 14 | [ 15 | { 16 | "citationID": "CITATION-1", 17 | "citationItems": [ 18 | { 19 | "id": "ITEM-1" 20 | } 21 | ], 22 | "properties": { 23 | "noteIndex": 0, 24 | "mode": "textual" 25 | } 26 | }, 27 | [], 28 | [] 29 | ], 30 | [ 31 | { 32 | "citationID": "CITATION-2", 33 | "citationItems": [ 34 | { 35 | "id": "ITEM-1" 36 | } 37 | ], 38 | "properties": { 39 | "noteIndex": 1 40 | } 41 | }, 42 | [], 43 | [] 44 | ] 45 | 46 | ] 47 | <<===== CITATIONS =====<< 48 | 49 | 50 | 51 | >>===== CSL =====>> 52 | 73 | <<===== CSL =====<< 74 | 75 | 76 | >>===== INPUT =====>> 77 | [ 78 | { 79 | "author": [ 80 | { 81 | "family": "Smith", 82 | "given": "John" 83 | } 84 | ], 85 | "issued": { 86 | "date-parts": [ 87 | [ 88 | 1986 89 | ] 90 | ] 91 | }, 92 | "type": "book", 93 | "id": "ITEM-1" 94 | } 95 | ] 96 | <<===== INPUT =====<< 97 | 98 | -------------------------------------------------------------------------------- /test/human/citation_LocatorOnly.txt: -------------------------------------------------------------------------------- 1 | >>===== MODE =====>> 2 | citation 3 | <<===== MODE =====<< 4 | 5 | 6 | >>===== RESULT =====>> 7 | (32) 8 | <<===== RESULT =====<< 9 | 10 | 11 | >>===== CITATIONS =====>> 12 | [ 13 | [ 14 | { 15 | "citationID": "CITATION-1", 16 | "citationItems": [ 17 | { 18 | "id": "ITEM-1", 19 | "locator": "32" 20 | } 21 | ], 22 | "properties": { 23 | "noteIndex": 0, 24 | "mode": "locator-only" 25 | } 26 | }, 27 | [], 28 | [] 29 | ] 30 | 31 | ] 32 | <<===== CITATIONS =====<< 33 | 34 | 35 | 36 | >>===== CSL =====>> 37 | 68 | <<===== CSL =====<< 69 | 70 | 71 | >>===== INPUT =====>> 72 | [ 73 | { 74 | "author": [ 75 | { 76 | "family": "Smith", 77 | "given": "John" 78 | } 79 | ], 80 | "title": "A nice title", 81 | "issued": { 82 | "date-parts": [ 83 | [ 84 | 1986 85 | ] 86 | ] 87 | }, 88 | "type": "book", 89 | "id": "ITEM-1" 90 | } 91 | ] 92 | <<===== INPUT =====<< 93 | -------------------------------------------------------------------------------- /test/citeproc-test-int-formatters.el: -------------------------------------------------------------------------------- 1 | ;;; citeproc-test-int-formatters.el --- formatter tests -*- lexical-binding: t; -*- 2 | 3 | (require 'ert) 4 | (require 'citeproc) 5 | (require 'citeproc-formatters) 6 | 7 | (ert-deftest citeproc-test-formatters-html () 8 | (let ((f (citeproc-formatter-rt 9 | (citeproc-formatter-for-format 'html)))) 10 | (should (string= (funcall f '(((href . "http://orgmode.org")) "Org website")) 11 | "Org website")))) 12 | 13 | (ert-deftest citeproc-test-formatters-org () 14 | (let ((f (citeproc-formatter-rt 15 | (citeproc-formatter-for-format 'org)))) 16 | (should (string= (funcall f '(((href . "http://orgmode.org")) "Org website")) 17 | "[[http://orgmode.org][Org website]]")) 18 | (should (string= (funcall f '(((href . "http://orgmode.org")) "http://orgmode.org")) 19 | "http://orgmode.org")) 20 | (should (string= (funcall f '(((bib-item-no . "1")) "text")) 21 | "<>text")))) 22 | 23 | (ert-deftest citeproc-test-formatters-plain () 24 | (let ((f (citeproc-formatter-rt 25 | (citeproc-formatter-for-format 'plain)))) 26 | (should (string= (funcall f '(((href . "http://orgmode.org")) "Org website")) 27 | "Org website")))) 28 | 29 | (ert-deftest citeproc-test-formatters-latex () 30 | (let ((f (citeproc-formatter-rt 31 | (citeproc-formatter-for-format 'latex)))) 32 | (should (string= (funcall f '(((href . "http://orgmode.org")) "Org website")) 33 | "\\href{http://orgmode.org}{Org website}")) 34 | (should (string= 35 | (funcall f 36 | '(((href . "https://scholar.google.com/scholar?q=%22functional+data%22")) 37 | "https://scholar.google.com/scholar?q=%22functional+data%22")) 38 | "\\url{https://scholar.google.com/scholar?q=\\%22functional+data\\%22}")))) 39 | 40 | (ert-deftest citeproc-test-formatters-csl () 41 | (let ((f (citeproc-formatter-rt 42 | (citeproc-formatter-for-format 'csl-test)))) 43 | (should (string= (funcall f '(((href . "http://orgmode.org")) "Org website")) 44 | "Org website")))) 45 | 46 | (provide 'citeproc-test-int-formatters) 47 | 48 | ;;; citeproc-test-int-formatters.el ends here 49 | -------------------------------------------------------------------------------- /test/biblatex_csl/thesis.txt: -------------------------------------------------------------------------------- 1 | --- 2 | @thesis{geer, 3 | Annotation = {This is a typical thesis entry for a PhD thesis. Note the type field in the database file which uses a localization key. Also note the format of the printed name and compare the useprefix option in the options field as well as vangennep}, 4 | Author = {de Geer, Ingrid}, 5 | Date = 1985, 6 | Institution = {Uppsala Universitet}, 7 | Location = {Uppsala}, 8 | Options = {useprefix=false}, 9 | Subtitle = {The {Orkney} earldom of the twelfth century. {A} musicological study}, 10 | Title = {Earl, saint, bishop, skald and music}, 11 | Type = {phdthesis}} 12 | 13 | @thesis{loh, 14 | Annotation = {This is a typical thesis entry for an MA thesis. Note the type field in the database file which uses a localization key}, 15 | Author = {Loh, Nin C.}, 16 | Date = 1992, 17 | Institution = {Massachusetts Institute of Technology}, 18 | Location = {Cambridge, Mass.}, 19 | Title = {High-resolution micromachined interferometric accelerometer}, 20 | Type = {mathesis}} 21 | --- 22 | - annote: This is a typical thesis entry for a PhD thesis. Note the type 23 | field in the database file which uses a localization key. Also note 24 | the format of the printed name and compare the useprefix option in 25 | the options field as well as vangennep 26 | author: 27 | - family: Geer 28 | given: Ingrid 29 | non-dropping-particle: de 30 | blt-type: thesis 31 | genre: PhD thesis 32 | id: geer 33 | issued: 1985 34 | publisher: Uppsala Universitet 35 | publisher-place: Uppsala 36 | title: "Earl, saint, bishop, skald and music: The Orkney earldom of 37 | the twelfth century. A musicological study" 38 | title-short: Earl, saint, bishop, skald and music 39 | type: thesis 40 | - annote: This is a typical thesis entry for an MA thesis. Note the type 41 | field in the database file which uses a localization key 42 | author: 43 | - family: Loh 44 | given: Nin C. 45 | blt-type: thesis 46 | genre: Master's thesis 47 | id: loh 48 | issued: 1992 49 | publisher: Massachusetts Institute of Technology 50 | publisher-place: Cambridge, Mass. 51 | title: High-resolution micromachined interferometric accelerometer 52 | type: thesis 53 | -------------------------------------------------------------------------------- /citeproc-macro.el: -------------------------------------------------------------------------------- 1 | ;; citeproc-macro.el --- functions to render CSL macros -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright (C) 2017 András Simonyi 4 | 5 | ;; Author: András Simonyi 6 | 7 | ;; This program is free software; you can redistribute it and/or modify 8 | ;; it under the terms of the GNU General Public License as published by 9 | ;; the Free Software Foundation, either version 3 of the License, or 10 | ;; (at your option) any later version. 11 | 12 | ;; This program is distributed in the hope that it will be useful, 13 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | ;; GNU General Public License for more details. 16 | 17 | ;; You should have received a copy of the GNU General Public License 18 | ;; along with this program. If not, see . 19 | 20 | ;; This file is not part of GNU Emacs. 21 | 22 | ;;; Commentary: 23 | 24 | ;; Functions to render the output of CSL macros. 25 | 26 | ;;; Code: 27 | 28 | (require 'citeproc-lib) 29 | (require 'citeproc-rt) 30 | (require 'citeproc-context) 31 | 32 | ;;; For macro evaluation 33 | (defun citeproc--macro (attrs context &rest body) 34 | "Render the content of a macro element with ATTRS and BODY." 35 | (let* ((spliced-body (citeproc-lib-splice-into body 'splice)) 36 | (val (citeproc-rt-typed-join attrs spliced-body context))) 37 | (if (eq 'empty-vars (cdr val)) 38 | (cons nil 'text-only) 39 | val))) 40 | 41 | (defun citeproc-macro-output (macro context) 42 | "Return the output of MACRO. 43 | MACRO is the macro's name as a string and the returned value is a 44 | (RICH-TEXT-CONTENT . CONTENT-TYPE) cons cell." 45 | (let ((macro-fun (assoc-default macro (citeproc-context-macros context)))) 46 | (if macro-fun 47 | (funcall macro-fun context) 48 | (error "There is no macro called `%s' in style" macro)))) 49 | 50 | (defun citeproc-macro-output-as-text (macro context) 51 | "Return the output of MACRO as plain text. 52 | MACRO is the macro's name as a string." 53 | (citeproc-rt-to-plain (citeproc-rt-render-affixes 54 | (car (citeproc-macro-output macro context))))) 55 | 56 | (provide 'citeproc-macro) 57 | 58 | ;;; citeproc-macro.el ends here 59 | -------------------------------------------------------------------------------- /test/biblatex_csl/online.txt: -------------------------------------------------------------------------------- 1 | --- 2 | @comment{adapted from http://mirrors.ctan.org/macros/latex/contrib/biblatex/doc/examples/biblatex-examples.bib} 3 | 4 | @online{markey, 5 | Annotation = {An online entry for a tutorial. Note the format of the date field (yyyy-mm-dd) in the database file.}, 6 | Author = {Markey, Nicolas}, 7 | Date = {2005-10-16}, 8 | Sorttitle = {Tame the Beast}, 9 | Subtitle = {The {B} to {X} of {BibTeX}}, 10 | Title = {Tame the {BeaST}}, 11 | Url = {http://tug.ctan.org/tex-archive/info/bibtex/tamethebeast/ttb_en.pdf}, 12 | Urldate = {2006-10-01}, 13 | Version = {1.3}, 14 | } 15 | 16 | @online{CTAN, 17 | Annotation = {This is an online entry. The url, which is given in the url field, is transformed into a clickable link if hyperref support has been enabled. Note the format of the urldate field (yyyy-mm-dd) in the database file. Also note the label field which may be used as a fallback by citation styles which need an author and/or a year}, 18 | Date = 2006, 19 | Label = {CTAN}, 20 | Subtitle = {The {Comprehensive TeX Archive Network}}, 21 | Title = {{CTAN}}, 22 | Url = {http://www.ctan.org}, 23 | Urldate = {2006-10-01}, 24 | } 25 | --- 26 | - accessed: 2006-10-01 27 | annote: An online entry for a tutorial. Note the format of the date 28 | field (yyyy-mm-dd) in the database file. 29 | author: 30 | - family: Markey 31 | given: Nicolas 32 | blt-type: online 33 | id: markey 34 | issued: 2005-10-16 35 | title: "Tame the BeaST: The B to X of BibTeX" 36 | title-short: Tame the BeaST 37 | type: webpage 38 | URL: "http://tug.ctan.org/tex-archive/info/bibtex/tamethebeast/ttb_en.pdf" 39 | version: 1.3 40 | - accessed: 2006-10-01 41 | annote: This is an online entry. The url, which is given 42 | in the url field, is transformed into a clickable link if hyperref 43 | support has been enabled. Note the format of the urldate field 44 | (yyyy-mm-dd) in the database file. Also note the label field which 45 | may be used as a fallback by citation styles which need an author 46 | and/or a year 47 | blt-type: online 48 | citation-label: "CTAN" 49 | id: CTAN 50 | issued: 2006 51 | title: "CTAN: The Comprehensive TeX Archive Network" 52 | title-short: CTAN 53 | type: webpage 54 | URL: "http://www.ctan.org" 55 | -------------------------------------------------------------------------------- /test/human/citation_Textual.txt: -------------------------------------------------------------------------------- 1 | >>===== MODE =====>> 2 | citation 3 | <<===== MODE =====<< 4 | 5 | 6 | >>===== RESULT =====>> 7 | Smith (1986) 8 | (Smith 1986) 9 | <<===== RESULT =====<< 10 | 11 | 12 | >>===== CITATIONS =====>> 13 | [ 14 | [ 15 | { 16 | "citationID": "CITATION-1", 17 | "citationItems": [ 18 | { 19 | "id": "ITEM-1" 20 | } 21 | ], 22 | "properties": { 23 | "noteIndex": 0, 24 | "mode": "textual" 25 | } 26 | }, 27 | [], 28 | [] 29 | ], 30 | [ 31 | { 32 | "citationID": "CITATION-2", 33 | "citationItems": [ 34 | { 35 | "id": "ITEM-1" 36 | } 37 | ], 38 | "properties": { 39 | "noteIndex": 1 40 | } 41 | }, 42 | [], 43 | [] 44 | ] 45 | 46 | ] 47 | <<===== CITATIONS =====<< 48 | 49 | 50 | 51 | >>===== CSL =====>> 52 | 81 | <<===== CSL =====<< 82 | 83 | 84 | >>===== INPUT =====>> 85 | [ 86 | { 87 | "author": [ 88 | { 89 | "family": "Smith", 90 | "given": "John" 91 | } 92 | ], 93 | "issued": { 94 | "date-parts": [ 95 | [ 96 | 1986 97 | ] 98 | ] 99 | }, 100 | "type": "book", 101 | "id": "ITEM-1" 102 | } 103 | ] 104 | <<===== INPUT =====<< 105 | 106 | -------------------------------------------------------------------------------- /test/human/citation_SuppressAuthor.txt: -------------------------------------------------------------------------------- 1 | >>===== MODE =====>> 2 | citation 3 | <<===== MODE =====<< 4 | 5 | 6 | >>===== RESULT =====>> 7 | (1986 A nice title) 8 | (Smith 1986 A nice title) 9 | <<===== RESULT =====<< 10 | 11 | 12 | >>===== CITATIONS =====>> 13 | [ 14 | [ 15 | { 16 | "citationID": "CITATION-1", 17 | "citationItems": [ 18 | { 19 | "id": "ITEM-1" 20 | } 21 | ], 22 | "properties": { 23 | "noteIndex": 0, 24 | "mode": "suppress-author" 25 | } 26 | }, 27 | [], 28 | [] 29 | ], 30 | [ 31 | { 32 | "citationID": "CITATION-1", 33 | "citationItems": [ 34 | { 35 | "id": "ITEM-1" 36 | } 37 | ], 38 | "properties": { 39 | "noteIndex": 0 40 | } 41 | }, 42 | [], 43 | [] 44 | ] 45 | ] 46 | <<===== CITATIONS =====<< 47 | 48 | 49 | 50 | >>===== CSL =====>> 51 | 81 | <<===== CSL =====<< 82 | 83 | 84 | >>===== INPUT =====>> 85 | [ 86 | { 87 | "author": [ 88 | { 89 | "family": "Smith", 90 | "given": "John" 91 | } 92 | ], 93 | "title": "A nice title", 94 | "issued": { 95 | "date-parts": [ 96 | [ 97 | 1986 98 | ] 99 | ] 100 | }, 101 | "type": "book", 102 | "id": "ITEM-1" 103 | } 104 | ] 105 | <<===== INPUT =====<< 106 | 107 | -------------------------------------------------------------------------------- /test/etc/subbibs.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | 4 | "id": "doe2001", 5 | "type": "article-journal", 6 | "container-title": "The Mind Scientific", 7 | "issue": "1", 8 | "page": "45-58", 9 | "title": "The Title", 10 | "volume": "103", 11 | "author": [ 12 | { 13 | "family": "Doe", 14 | "given": "John" 15 | } 16 | ], 17 | "issued": { 18 | "date-parts": [ 19 | [ 20 | "2001", 21 | 3 22 | ] 23 | ] 24 | }, 25 | "keyword": "primary,philosophy" 26 | }, 27 | { 28 | "id": "smith1952", 29 | "type": "book", 30 | "title": "The Book Title", 31 | "author": [ 32 | { 33 | "family": "Smith", 34 | "given": "Peter" 35 | } 36 | ], 37 | "issued": { 38 | "date-parts": [ 39 | [ 40 | "1952" 41 | ] 42 | ] 43 | }, 44 | "keyword": "primary" 45 | }, 46 | { 47 | "id": "doe1972", 48 | "type": "book", 49 | "title": "The Second Book Title", 50 | "author": [ 51 | { 52 | "family": "Doe", 53 | "given": "Jane" 54 | } 55 | ], 56 | "issued": { 57 | "date-parts": [ 58 | [ 59 | "1972" 60 | ] 61 | ] 62 | } 63 | }, 64 | { 65 | "id": "doe1972b", 66 | "type": "book", 67 | "title": "The Second 1972 Jane Doe book", 68 | "author": [ 69 | { 70 | "family": "Doe", 71 | "given": "Jane" 72 | } 73 | ], 74 | "issued": { 75 | "date-parts": [ 76 | [ 77 | "1972" 78 | ] 79 | ] 80 | }, 81 | "keyword": "secondary" 82 | }, 83 | { 84 | "id": "doe1972c", 85 | "type": "book", 86 | "title": "The Third 1972 Jane Doe book", 87 | "author": [ 88 | { 89 | "family": "Doe", 90 | "given": "Jane" 91 | } 92 | ], 93 | "issued": { 94 | "date-parts": [ 95 | [ 96 | "1972" 97 | ] 98 | ] 99 | }, 100 | "keyword": "primary" 101 | } 102 | ] 103 | -------------------------------------------------------------------------------- /test/human/citation_TextualCapitalizeFirst.txt: -------------------------------------------------------------------------------- 1 | >>===== MODE =====>> 2 | citation 3 | <<===== MODE =====<< 4 | 5 | 6 | >>===== RESULT =====>> 7 | (della Robbia 1986) 8 | Della Robbia (1986) 9 | <<===== RESULT =====<< 10 | 11 | 12 | >>===== CITATIONS =====>> 13 | [ 14 | [ 15 | { 16 | "citationID": "CITATION-1", 17 | "citationItems": [ 18 | { 19 | "id": "ITEM-1" 20 | } 21 | ], 22 | "properties": { 23 | "noteIndex": 0 24 | 25 | } 26 | }, 27 | [], 28 | [] 29 | ], 30 | [ 31 | { 32 | "citationID": "CITATION-1", 33 | "citationItems": [ 34 | { 35 | "id": "ITEM-1" 36 | } 37 | ], 38 | "properties": { 39 | "noteIndex": 1, 40 | "capitalize-first": 1, 41 | "mode": "textual" 42 | } 43 | }, 44 | [], 45 | [] 46 | ] 47 | ] 48 | <<===== CITATIONS =====<< 49 | 50 | 51 | 52 | >>===== CSL =====>> 53 | 82 | <<===== CSL =====<< 83 | 84 | 85 | >>===== INPUT =====>> 86 | [ 87 | { 88 | "author": [ 89 | { 90 | "family": "della Robbia", 91 | "given": "Luca" 92 | } 93 | ], 94 | "title": "A nice title", 95 | "issued": { 96 | "date-parts": [ 97 | [ 98 | 1986 99 | ] 100 | ] 101 | }, 102 | "type": "book", 103 | "id": "ITEM-1" 104 | } 105 | ] 106 | <<===== INPUT =====<< 107 | 108 | -------------------------------------------------------------------------------- /test/human/intlink_NonNoteStyle.txt: -------------------------------------------------------------------------------- 1 | >>===== OUTPUT-FORMAT =====>> 2 | org 3 | <<===== OUTPUT-FORMAT =====<< 4 | 5 | >>===== MODE =====>> 6 | citation 7 | <<===== MODE =====<< 8 | 9 | 10 | >>===== RESULT =====>> 11 | Smith ([[citeproc_bib_item_1][1986]]) 12 | ([[citeproc_bib_item_1][Smith 1986]]) 13 | <<===== RESULT =====<< 14 | 15 | 16 | >>===== CITATIONS =====>> 17 | [ 18 | [ 19 | { 20 | "citationID": "CITATION-1", 21 | "citationItems": [ 22 | { 23 | "id": "ITEM-1" 24 | } 25 | ], 26 | "properties": { 27 | "noteIndex": 0, 28 | "mode": "textual" 29 | } 30 | }, 31 | [], 32 | [] 33 | ], 34 | [ 35 | { 36 | "citationID": "CITATION-2", 37 | "citationItems": [ 38 | { 39 | "id": "ITEM-1" 40 | } 41 | ], 42 | "properties": { 43 | "noteIndex": 1 44 | } 45 | }, 46 | [], 47 | [] 48 | ] 49 | 50 | ] 51 | <<===== CITATIONS =====<< 52 | 53 | 54 | 55 | >>===== CSL =====>> 56 | 85 | <<===== CSL =====<< 86 | 87 | 88 | >>===== INPUT =====>> 89 | [ 90 | { 91 | "author": [ 92 | { 93 | "family": "Smith", 94 | "given": "John" 95 | } 96 | ], 97 | "issued": { 98 | "date-parts": [ 99 | [ 100 | 1986 101 | ] 102 | ] 103 | }, 104 | "type": "book", 105 | "id": "ITEM-1" 106 | } 107 | ] 108 | <<===== INPUT =====<< 109 | 110 | -------------------------------------------------------------------------------- /test/human/intlink_NoteStyle.txt: -------------------------------------------------------------------------------- 1 | >>===== OUTPUT-FORMAT =====>> 2 | org 3 | <<===== OUTPUT-FORMAT =====<< 4 | 5 | >>===== MODE =====>> 6 | citation 7 | <<===== MODE =====<< 8 | 9 | >>===== RESULT =====>> 10 | (<>Smith 1986) 11 | ([[citeproc_bib_item_1][Smith 1986]]) 12 | <<===== RESULT =====<< 13 | 14 | 15 | >>===== CITATIONS =====>> 16 | [ 17 | [ 18 | { 19 | "citationID": "CITATION-1", 20 | "citationItems": [ 21 | { 22 | "id": "ITEM-1" 23 | } 24 | ], 25 | "properties": { 26 | "noteIndex": 0 27 | } 28 | }, 29 | [], 30 | [] 31 | ], 32 | [ 33 | { 34 | "citationID": "CITATION-2", 35 | "citationItems": [ 36 | { 37 | "id": "ITEM-1" 38 | } 39 | ], 40 | "properties": { 41 | "noteIndex": 1 42 | } 43 | }, 44 | [], 45 | [] 46 | ] 47 | 48 | ] 49 | <<===== CITATIONS =====<< 50 | 51 | 52 | 53 | >>===== CSL =====>> 54 | 84 | <<===== CSL =====<< 85 | 86 | 87 | >>===== INPUT =====>> 88 | [ 89 | { 90 | "author": [ 91 | { 92 | "family": "Smith", 93 | "given": "John" 94 | } 95 | ], 96 | "issued": { 97 | "date-parts": [ 98 | [ 99 | 1986 100 | ] 101 | ] 102 | }, 103 | "type": "book", 104 | "id": "ITEM-1" 105 | } 106 | ] 107 | <<===== INPUT =====<< 108 | 109 | -------------------------------------------------------------------------------- /test/human/citation_ApplyModeAfterSortingCites.txt: -------------------------------------------------------------------------------- 1 | >>===== MODE =====>> 2 | citation 3 | <<===== MODE =====<< 4 | 5 | 6 | >>===== RESULT =====>> 7 | Smith (1986, 1992) 8 | <<===== RESULT =====<< 9 | 10 | 11 | >>===== CITATIONS =====>> 12 | [ 13 | [ 14 | { 15 | "citationID": "CITATION-1", 16 | "citationItems": [ 17 | { 18 | "id": "ITEM-2" 19 | }, 20 | { 21 | "id": "ITEM-1" 22 | } 23 | ], 24 | "properties": { 25 | "noteIndex": 0, 26 | "mode": "textual" 27 | } 28 | }, 29 | [], 30 | [] 31 | ] 32 | ] 33 | <<===== CITATIONS =====<< 34 | 35 | 36 | 37 | >>===== CSL =====>> 38 | 71 | <<===== CSL =====<< 72 | 73 | 74 | >>===== INPUT =====>> 75 | [ 76 | { 77 | "author": [ 78 | { 79 | "family": "Smith", 80 | "given": "John" 81 | } 82 | ], 83 | "issued": { 84 | "date-parts": [ 85 | [ 86 | 1986 87 | ] 88 | ] 89 | }, 90 | "type": "book", 91 | "id": "ITEM-1" 92 | }, 93 | { 94 | "author": [ 95 | { 96 | "family": "Smith", 97 | "given": "John" 98 | } 99 | ], 100 | "issued": { 101 | "date-parts": [ 102 | [ 103 | 1992 104 | ] 105 | ] 106 | }, 107 | "type": "book", 108 | "id": "ITEM-2" 109 | } 110 | ] 111 | <<===== INPUT =====<< 112 | 113 | -------------------------------------------------------------------------------- /test/biblatex_csl/article.txt: -------------------------------------------------------------------------------- 1 | --- 2 | @article{article-req, 3 | Author = {Author, Ann}, 4 | Date = {2013-01-01}, 5 | Journaltitle = {The Journaltitle}, 6 | Title = {An article entry with just the required fields}, 7 | Langid = {english}}, 8 | 9 | @article{article-opt, 10 | Addendum = {The Addendum}, 11 | Annotator = {Annotator, A.}, 12 | Author = {Author, Jr., Ann A.}, 13 | Commentator = {Commentator, C.}, 14 | Date = {2013-01-01}, 15 | Doi = {10.1086/520976}, 16 | Editor = {Editor, Edward}, 17 | Editora = {Editor, A.}, 18 | Editorb = {Editor, B.}, 19 | Editorc = {Editor, C.}, 20 | Eid = {eid}, 21 | Eprint = {eprint}, 22 | Eprintclass = {eprintclass}, 23 | Eprinttype = {eprinttype}, 24 | Issn = {issn}, 25 | Issue = {issue}, 26 | Issuesubtitle = {The Issuesubtitle}, 27 | Issuetitle = {The Issuetitle}, 28 | Journalsubtitle = {The Journalsubtitle}, 29 | Journaltitle = {The Journaltitle}, 30 | Journal = {The Journal}, 31 | Language = {language}, 32 | Month = {01}, 33 | Year = {2013}, 34 | Note = {The Note}, 35 | Number = {number}, 36 | Origlanguage = {origlanguage}, 37 | Pages = {pages}, 38 | Pubstate = {in press}, 39 | Series = {new series}, 40 | Subtitle = {The subtitle}, 41 | Title = {An article entry with the required and all optional fields}, 42 | Titleaddon = {The titleaddon}, 43 | Translator = {Translator, Ted}, 44 | Url = {http://foo.bar.baz/}, 45 | Urldate = {2013-01-01}, 46 | Version = {version}, 47 | Volume = {volume}, 48 | Langid = {english} 49 | } 50 | --- 51 | - author: 52 | - family: Author 53 | given: Ann 54 | blt-type: article 55 | container-title: The journaltitle 56 | id: article-req 57 | issued: 2013-01-01 58 | language: en-US 59 | title: An article entry with just the required fields 60 | type: article-journal 61 | - accessed: 2013-01-01 62 | author: 63 | - family: Author 64 | given: Ann A. 65 | suffix: Jr. 66 | blt-type: article 67 | collection-title: New series 68 | container-title: "The journaltitle: The journalsubtitle" 69 | DOI: 10.1086/520976 70 | editor: 71 | - family: Editor 72 | given: Edward 73 | blt-type: article 74 | id: article-opt 75 | ISSN: issn 76 | issue: number, issue 77 | issued: 2013-01-01 78 | language: en-US 79 | note: The Note. The Addendum 80 | page: pages 81 | status: in press 82 | title: "An article entry with the required and all optional fields: 83 | The subtitle. The titleaddon" 84 | title-short: An article entry with the required and all optional 85 | fields 86 | translator: 87 | - family: Translator 88 | given: Ted 89 | type: article-journal 90 | URL: "http://foo.bar.baz/" 91 | version: version 92 | volume: volume 93 | -------------------------------------------------------------------------------- /test/human/citation_IgnoreEtAl.txt: -------------------------------------------------------------------------------- 1 | >>===== MODE =====>> 2 | citation 3 | <<===== MODE =====<< 4 | 5 | 6 | >>===== RESULT =====>> 7 | (Smith et al. 1986) 8 | (Smith, Doe, Taylor & Carpenter 1986) 9 | <<===== RESULT =====<< 10 | 11 | 12 | >>===== CITATIONS =====>> 13 | [ 14 | [ 15 | { 16 | "citationID": "CITATION-1", 17 | "citationItems": [ 18 | { 19 | "id": "ITEM-1" 20 | } 21 | ], 22 | "properties": { 23 | "noteIndex": 0 24 | 25 | } 26 | }, 27 | [], 28 | [] 29 | ], 30 | [ 31 | { 32 | "citationID": "CITATION-1", 33 | "citationItems": [ 34 | { 35 | "id": "ITEM-1" 36 | } 37 | ], 38 | "properties": { 39 | "noteIndex": 0, 40 | "ignore-et-al": 1 41 | } 42 | }, 43 | [], 44 | [] 45 | ] 46 | ] 47 | <<===== CITATIONS =====<< 48 | 49 | 50 | 51 | >>===== CSL =====>> 52 | 81 | <<===== CSL =====<< 82 | 83 | 84 | >>===== INPUT =====>> 85 | [ 86 | { 87 | "author": [ 88 | { 89 | "family": "Smith", 90 | "given": "John" 91 | }, 92 | { 93 | "family": "Doe", 94 | "given": "Jane" 95 | }, 96 | { 97 | "family": "Taylor", 98 | "given": "Tom" 99 | }, 100 | { 101 | "family": "Carpenter", 102 | "given": "Emma" 103 | } 104 | 105 | ], 106 | "title": "A nice title", 107 | "issued": { 108 | "date-parts": [ 109 | [ 110 | 1986 111 | ] 112 | ] 113 | }, 114 | "type": "book", 115 | "id": "ITEM-1" 116 | } 117 | ] 118 | <<===== INPUT =====<< 119 | 120 | -------------------------------------------------------------------------------- /test/biblatex_csl/inproceedings.txt: -------------------------------------------------------------------------------- 1 | --- 2 | @string{cup = {Cambridge University Press}} 3 | 4 | @inproceedings{moraux, 5 | Annotation = {This is a typical inproceedings entry. Note the booksubtitle, shorttitle, indextitle, and indexsorttitle fields. Also note the eventdate field.}, 6 | Author = {Moraux, Paul}, 7 | Booktitle = {Aristotle on Mind and the Senses}, 8 | Booktitleaddon = {Proceedings of the Seventh Symposium Aristotelicum}, 9 | Date = 1979, 10 | Editor = {Lloyd, G. E. R. and Owen, G. E. L.}, 11 | Eventdate = 1975, 12 | Indexsorttitle = {De Anima dans la tradition grecque}, 13 | Indextitle = {De Anima dans la tradition grècque, Le}, 14 | Keywords = {secondary}, 15 | Location = {Cambridge}, 16 | Pages = {281-324}, 17 | Publisher = cup, 18 | Shorttitle = {De Anima dans la tradition grècque}, 19 | Subtitle = {Quelques aspects de l'interpretation du traité, de Theophraste à Themistius}, 20 | Title = {Le De Anima dans la tradition grècque}, 21 | Langid = {french}} 22 | 23 | @inproceedings{salam, 24 | Author = {Salam, Abdus}, 25 | Booksubtitle = {Relativistic groups and analyticity}, 26 | Booktitle = {Elementary particle theory}, 27 | Booktitleaddon = {Proceedings of the Eighth {Nobel} Symposium}, 28 | Date = 1968, 29 | Editor = {Svartholm, Nils}, 30 | Eventdate = {1968-05-19/1968-05-25}, 31 | Location = {Stockholm}, 32 | Pages = {367-377}, 33 | Publisher = {Almquist \& Wiksell}, 34 | Title = {Weak and Electromagnetic Interactions}, 35 | Venue = {Aspenäsgarden, Lerum}} 36 | --- 37 | - annote: This is a typical inproceedings entry. Note the booksubtitle, 38 | shorttitle, indextitle, and indexsorttitle fields. Also note the 39 | eventdate field. 40 | author: 41 | - family: Moraux 42 | given: Paul 43 | blt-type: inproceedings 44 | container-title: Aristotle on Mind and the Senses. Proceedings of the 45 | Seventh Symposium Aristotelicum 46 | editor: 47 | - family: Lloyd 48 | given: G. E. R. 49 | - family: Owen 50 | given: G. E. L. 51 | event-date: 1975 52 | id: moraux 53 | issued: 1979 54 | language: fr-FR 55 | keyword: secondary 56 | page: 281-324 57 | publisher: Cambridge University Press 58 | publisher-place: Cambridge 59 | title: "Le De Anima dans la tradition grècque: Quelques aspects de 60 | l'interpretation du traité, de Theophraste à Themistius" 61 | title-short: "De Anima dans la tradition grècque" 62 | type: paper-conference 63 | - author: 64 | - family: Salam 65 | given: Abdus 66 | blt-type: inproceedings 67 | container-title: "Elementary particle theory: Relativistic groups and 68 | analyticity. Proceedings of the eighth Nobel symposium" 69 | editor: 70 | - family: Svartholm 71 | given: Nils 72 | event-date: 1968-05-19/1968-05-25 73 | event-place: Aspenäsgarden, Lerum 74 | id: salam 75 | issued: 1968 76 | page: 367-377 77 | publisher: Almquist & Wiksell 78 | publisher-place: Stockholm 79 | title: Weak and electromagnetic interactions 80 | type: paper-conference 81 | -------------------------------------------------------------------------------- /test/biblatex_csl/inspect.org: -------------------------------------------------------------------------------- 1 | * Test 2 | 3 | #+begin_src emacs-lisp 4 | (setq citeproc-test-blt-current "thesis") 5 | #+end_src 6 | 7 | #+RESULTS: 8 | : thesis 9 | 10 | * Expected 11 | 12 | #+begin_src emacs-lisp :results value code 13 | (let* ((file (concat "./" citeproc-test-blt-current ".txt")) 14 | (csl-entries (cdr 15 | (citeproc-test-blt--parse file)))) 16 | (citeproc-test-blt--normalize-csl-entries 17 | csl-entries)) 18 | #+end_src 19 | 20 | #+RESULTS: 21 | #+begin_src emacs-lisp 22 | (((annote . "This is a typical thesis entry for a PhD thesis. Note the type field in the database file which uses a localization key. Also note the format of the printed name and compare the useprefix option in the options field as well as vangennep") 23 | (author 24 | ((dropping-particle . "de") 25 | (family . "Geer") 26 | (given . "Ingrid"))) 27 | (genre . "PhD thesis") 28 | (id . "geer") 29 | (issued 30 | (date-parts 31 | (1985))) 32 | (publisher . "Uppsala Universitet") 33 | (publisher-place . "Uppsala") 34 | (title . "Earl, saint, bishop, skald and music: The Orkney earldom of the twelfth century. A musicological study") 35 | (title-short . "Earl, saint, bishop, skald and music") 36 | (type . "thesis")) 37 | ((annote . "This is a typical thesis entry for an MA thesis. Note the type field in the database file which uses a localization key") 38 | (author 39 | ((family . "Loh") 40 | (given . "Nin C."))) 41 | (genre . "Master's thesis") 42 | (id . "loh") 43 | (issued 44 | (date-parts 45 | (1992))) 46 | (publisher . "Massachusetts Institute of Technology") 47 | (publisher-place . "Cambridge, Mass.") 48 | (title . "High-resolution micromachined interferometric accelerometer") 49 | (type . "thesis"))) 50 | #+end_src 51 | * Output 52 | #+begin_src emacs-lisp :results value code 53 | (let* ((file (concat "./" citeproc-test-blt-current ".txt")) 54 | (blt (car 55 | (citeproc-test-blt--parse file)))) 56 | (citeproc-test-blt--output blt)) 57 | #+end_src 58 | 59 | #+RESULTS: 60 | #+begin_src emacs-lisp 61 | (((annote . "This is a typical thesis entry for a PhD thesis. Note the type field in the database file which uses a localization key. Also note the format of the printed name and compare the useprefix option in the options field as well as vangennep") 62 | (author 63 | ((dropping-particle . "de") 64 | (family . "Geer") 65 | (given . "Ingrid"))) 66 | (genre . "PhD thesis") 67 | (id . "geer") 68 | (issued 69 | (date-parts 70 | (1985))) 71 | (publisher . "Uppsala Universitet") 72 | (publisher-place . "Uppsala") 73 | (title . "Earl, Saint, Bishop, Skald and Music: The Orkney Earldom of the Twelfth Century. A Musicological Study") 74 | (title-short . "Earl, Saint, Bishop, Skald and Music") 75 | (type . "thesis")) 76 | ((annote . "This is a typical thesis entry for an MA thesis. Note the type field in the database file which uses a localization key") 77 | (author 78 | ((family . "Loh") 79 | (given . "Nin C."))) 80 | (genre . "Master's thesis") 81 | (id . "loh") 82 | (issued 83 | (date-parts 84 | (1992))) 85 | (publisher . "Massachusetts Institute of Technology") 86 | (publisher-place . "Cambridge, Mass.") 87 | (title . "High-Resolution Micromachined Interferometric Accelerometer") 88 | (type . "thesis"))) 89 | #+end_src 90 | 91 | -------------------------------------------------------------------------------- /citeproc-subbibs.el: -------------------------------------------------------------------------------- 1 | ;;; citeproc-subbibs.el --- support for subbibliographies -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright (C) 2021-2022 András Simonyi 4 | 5 | ;; Author: András Simonyi 6 | 7 | ;; This program is free software; you can redistribute it and/or modify 8 | ;; it under the terms of the GNU General Public License as published by 9 | ;; the Free Software Foundation, either version 3 of the License, or 10 | ;; (at your option) any later version. 11 | 12 | ;; This program is distributed in the hope that it will be useful, 13 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | ;; GNU General Public License for more details. 16 | 17 | ;; You should have received a copy of the GNU General Public License 18 | ;; along with this program. If not, see . 19 | 20 | ;; This file is not part of GNU Emacs. 21 | 22 | ;;; Commentary: 23 | 24 | ;; Support for generating subbibliographies based on filtering items. 25 | 26 | ;;; Code: 27 | 28 | (require 'subr-x) 29 | (require 'compat) 30 | (require 'dash) 31 | 32 | (require 'citeproc-proc) 33 | (require 'citeproc-itemdata) 34 | 35 | (defun citeproc-sb--match-p (vv filter) 36 | "Return whether var-vals alist VV matches all conditions in FILTER. 37 | FILTER should be an alist containing symbol keys and string 38 | values, each pair describing an atomic condition to be 39 | satisified. For a list and description of the supported keys 40 | see the documentation of `citeproc-add-subbib-filters'." 41 | (let* ((csl-type (alist-get 'type vv)) 42 | (type (or (alist-get 'blt-type vv) csl-type)) 43 | (keyword (alist-get 'keyword vv)) 44 | (keywords (and keyword (mapcar #'string-clean-whitespace 45 | (split-string keyword "[,;]" t))))) 46 | (--every-p 47 | (pcase it 48 | (`(type . ,key) (string= type key)) 49 | (`(nottype . ,key) (not (string= type key))) 50 | (`(keyword . ,key) (member key keywords)) 51 | (`(notkeyword . ,key) (not (member key keywords))) 52 | (`(filter . ,key) (funcall (intern key) vv)) 53 | (`(csltype . ,key) (string= csl-type key)) 54 | (`(notcsltype . ,key) (not (string= csl-type key))) 55 | (`(,key . ,_) (error "Unsupported Citeproc filter keyword `%s'" key))) 56 | filter))) 57 | 58 | (defun citeproc-sb-add-subbib-info (proc) 59 | "Add subbibliography information to the items in PROC." 60 | (when (citeproc-proc-filtered-bib-p proc) 61 | (let ((filters (citeproc-proc-bib-filters proc))) 62 | (maphash 63 | (lambda (_ itemdata) 64 | (let* ((varvals (citeproc-itemdata-varvals itemdata)) 65 | (subbib-nos 66 | (-non-nil 67 | (--map-indexed 68 | (when (citeproc-sb--match-p varvals it) it-index) 69 | filters)))) 70 | (setf (citeproc-itemdata-subbib-nos itemdata) subbib-nos))) 71 | (citeproc-proc-itemdata proc))))) 72 | 73 | (defun citeproc-sb-prune-unrendered (proc) 74 | "Remove all itemdata about unrendered items from PROC. 75 | An item is unrendered if 76 | - there are subbibfilters but none of them matches it, and 77 | - it is not cited." 78 | (when (citeproc-proc-filtered-bib-p proc) 79 | (let ((itemdata (citeproc-proc-itemdata proc))) 80 | (maphash 81 | (lambda (id data) 82 | (when (and (citeproc-itemdata-uncited data) 83 | (null (citeproc-itemdata-subbib-nos data))) 84 | (remhash id itemdata))) 85 | itemdata)))) 86 | 87 | (provide 'citeproc-subbibs) 88 | 89 | ;;; citeproc-subbibs.el ends here 90 | -------------------------------------------------------------------------------- /test/human/citation_TextualGroupedCites.txt: -------------------------------------------------------------------------------- 1 | >>===== MODE =====>> 2 | citation 3 | <<===== MODE =====<< 4 | 5 | 6 | >>===== RESULT =====>> 7 | Smith (1986, 1992; Doe 1971) 8 | Doe (1971; Smith 1986, 1992) 9 | <<===== RESULT =====<< 10 | 11 | 12 | >>===== CITATIONS =====>> 13 | [ 14 | [ 15 | { 16 | "citationID": "CITATION-1", 17 | "citationItems": [ 18 | { 19 | "id": "ITEM-1" 20 | }, 21 | { 22 | "id": "ITEM-2" 23 | }, 24 | { 25 | "id": "ITEM-3" 26 | } 27 | ], 28 | "properties": { 29 | "noteIndex": 0, 30 | "mode": "textual" 31 | } 32 | }, 33 | [], 34 | [] 35 | ], 36 | [ 37 | { 38 | "citationID": "CITATION-2", 39 | "citationItems": [ 40 | { 41 | "id": "ITEM-3" 42 | }, 43 | { 44 | "id": "ITEM-1" 45 | }, 46 | { 47 | "id": "ITEM-2" 48 | } 49 | ], 50 | "properties": { 51 | "noteIndex": 1, 52 | "mode": "textual" 53 | } 54 | }, 55 | [], 56 | [] 57 | ] 58 | 59 | ] 60 | <<===== CITATIONS =====<< 61 | 62 | 63 | 64 | >>===== CSL =====>> 65 | 95 | <<===== CSL =====<< 96 | 97 | 98 | >>===== INPUT =====>> 99 | [ 100 | { 101 | "author": [ 102 | { 103 | "family": "Smith", 104 | "given": "John" 105 | } 106 | ], 107 | "issued": { 108 | "date-parts": [ 109 | [ 110 | 1986 111 | ] 112 | ] 113 | }, 114 | "type": "book", 115 | "id": "ITEM-1" 116 | }, 117 | { 118 | "author": [ 119 | { 120 | "family": "Smith", 121 | "given": "John" 122 | } 123 | ], 124 | "issued": { 125 | "date-parts": [ 126 | [ 127 | 1992 128 | ] 129 | ] 130 | }, 131 | "type": "book", 132 | "id": "ITEM-2" 133 | }, 134 | { 135 | "author": [ 136 | { 137 | "family": "Doe", 138 | "given": "Peter" 139 | } 140 | ], 141 | "issued": { 142 | "date-parts": [ 143 | [ 144 | 1971 145 | ] 146 | ] 147 | }, 148 | "type": "book", 149 | "id": "ITEM-3" 150 | } 151 | 152 | ] 153 | <<===== INPUT =====<< 154 | 155 | -------------------------------------------------------------------------------- /citeproc-locale.el: -------------------------------------------------------------------------------- 1 | ;; citeproc-locale.el --- CSL locale related functions -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright (C) 2017-2022 András Simonyi 4 | 5 | ;; Author: András Simonyi 6 | 7 | ;; This program is free software; you can redistribute it and/or modify 8 | ;; it under the terms of the GNU General Public License as published by 9 | ;; the Free Software Foundation, either version 3 of the License, or 10 | ;; (at your option) any later version. 11 | 12 | ;; This program is distributed in the hope that it will be useful, 13 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | ;; GNU General Public License for more details. 16 | 17 | ;; You should have received a copy of the GNU General Public License 18 | ;; along with this program. If not, see . 19 | 20 | ;; This file is not part of GNU Emacs. 21 | 22 | ;;; Commentary: 23 | 24 | ;; In addition to some locale handling helpers, this file provides the function 25 | ;; `citeproc-locale-getter-from-dir', which constructs locale getter functions 26 | ;; that retrieve locales from a given directory. 27 | 28 | ;;; Code: 29 | 30 | (require 'dash) 31 | (require 'f) 32 | (require 's) 33 | 34 | (require 'citeproc-lib) 35 | (require 'citeproc-term) 36 | 37 | (defconst citeproc-locale--default-variants-alist 38 | '(("af" . "ZA") ("ca" . "AD") ("cs" . "CZ") ("cy" . "GB") 39 | ("da" . "DK") ("en" . "US") ("el" . "GR") ("et" . "EE") 40 | ("fa" . "IR") ("he" . "IR") ("ja" . "JP") ("km" . "KH") 41 | ("ko" . "KR") ("nb" . "NO") ("nn" . "NO") ("sl" . "SI") 42 | ("sr" . "RS") ("sv" . "SE") ("uk" . "UA") ("vi" . "VN") 43 | ("zh" . "CN")) 44 | "Alist mapping locales to their default variants. 45 | Only those locales are given for which the default variant is not 46 | simply the result of upcasing.") 47 | 48 | (defconst citeproc-locale--simple-locales 49 | '("la" "eu" "ar") 50 | "List of simple locale names (without dash).") 51 | 52 | (defun citeproc-locale--extend (loc) 53 | "Extend simple locale LOC to default variant." 54 | (let ((variant (assoc-default loc citeproc-locale--default-variants-alist))) 55 | (concat loc "-" (or variant (s-upcase loc))))) 56 | 57 | (defun citeproc-locale--compatible-p (l1 l2) 58 | "Whether locales L1 and L2 are compatible." 59 | (or (not (and l1 l2)) 60 | (s-prefix-p l1 l2) 61 | (s-prefix-p l2 l1))) 62 | 63 | (defun citeproc-locale-getter-from-dir (dir) 64 | "Return a locale getter getting parsed locales from a local DIR. 65 | If the requested locale couldn't be read then return the parsed 66 | en-US locale, which must exist, and warn the user." 67 | (let ((default-loc-file (f-join dir "locales-en-US.xml"))) 68 | (lambda (loc) 69 | (let* ((ext-loc (if (or (member loc citeproc-locale--simple-locales) 70 | (s-contains-p "-" loc)) 71 | loc 72 | (citeproc-locale--extend loc))) 73 | (loc-file (concat dir "/locales-" ext-loc ".xml")) 74 | (loc-available (f-readable-p loc-file))) 75 | (citeproc-lib-remove-xml-comments 76 | (citeproc-lib-parse-xml-file 77 | (if loc-available loc-file 78 | (if (not (f-readable-p default-loc-file)) 79 | (error 80 | "The default CSL locale file %s doesn't exist or is unreadable" 81 | default-loc-file) 82 | (display-warning 83 | 'citeproc 84 | (format 85 | "Could not read CSL locale file %s, using the fallback en-US locale" 86 | loc-file)) 87 | default-loc-file)))))))) 88 | 89 | (defun citeproc-locale-termlist-from-xml-frag (frag) 90 | "Transform xml FRAG representing citeproc--terms into a citeproc-term list." 91 | (--mapcat (if (eq 'term (car it)) 92 | (citeproc-term--from-xml-frag (cdr it)) 93 | nil) 94 | frag)) 95 | 96 | (provide 'citeproc-locale) 97 | 98 | ;;; citeproc-locale.el ends here 99 | -------------------------------------------------------------------------------- /test/citeproc-test-int-subbibs.el: -------------------------------------------------------------------------------- 1 | ;;; citeproc-test-int-subbibs.el --- subbib tests -*- lexical-binding: t; -*- 2 | 3 | (require 'citeproc) 4 | 5 | (require 'ert) 6 | 7 | (defvar citeproc-test-int-root-dir "./test/") 8 | 9 | (ert-deftest citeproc-test-int-sb/add-subbib-info () 10 | (let* ((ig (citeproc-itemgetter-from-csl-json 11 | (concat citeproc-test-int-root-dir "etc/subbibs.json"))) 12 | (lg (citeproc-locale-getter-from-dir 13 | (concat citeproc-test-int-root-dir "locales"))) 14 | (proc (citeproc-create 15 | (concat citeproc-test-int-root-dir "etc/chicago-author-date.csl") ig lg))) 16 | (citeproc-add-uncited '("doe2001" "smith1952" "doe1972") proc) 17 | (setf (citeproc-proc-bib-filters proc) 18 | '(((type . "book")) 19 | ((type . "article-journal")) 20 | ((keyword . "primary")) 21 | ((notkeyword . "primary") (nottype . "article-journal")))) 22 | (citeproc-proc-finalize proc) 23 | (citeproc-sb-add-subbib-info proc) 24 | (should (equal (citeproc-itemdata-subbib-nos 25 | (gethash "doe2001" (citeproc-proc-itemdata proc))) 26 | '(1 2))) 27 | (should (equal (citeproc-itemdata-subbib-nos 28 | (gethash "smith1952" (citeproc-proc-itemdata proc))) 29 | '(0 2))) 30 | (should (equal (citeproc-itemdata-subbib-nos 31 | (gethash "doe1972" (citeproc-proc-itemdata proc))) 32 | '(0 3))))) 33 | 34 | (ert-deftest citeproc-test-int-sb/end2end () 35 | (let* ((ig (citeproc-itemgetter-from-csl-json 36 | (concat citeproc-test-int-root-dir "etc/subbibs.json"))) 37 | (lg (citeproc-locale-getter-from-dir 38 | (concat citeproc-test-int-root-dir "locales"))) 39 | (proc (citeproc-create 40 | (concat citeproc-test-int-root-dir "etc/chicago-author-date.csl") ig lg))) 41 | ;; Basic subdivision according to type 42 | (citeproc-add-uncited '("doe2001" "smith1952" "doe1972") proc) 43 | (citeproc-add-subbib-filters 44 | '(((type . "book")) 45 | ((type . "article-journal"))) 46 | proc) 47 | (should (equal (car (citeproc-render-bib proc 'plain)) 48 | '("Doe, Jane. 1972. The Second Book Title.\n\nSmith, Peter. 1952. The Book Title." 49 | "Doe, John. 2001. “The Title.” The Mind Scientific 103 (1): 45–58."))) 50 | (citeproc-clear proc) 51 | ;; Subsequent author substitution 52 | (citeproc-add-uncited '("doe1972" "doe1972b" "doe1972c") proc) 53 | (citeproc-add-subbib-filters 54 | '(((type . "book")) 55 | ((keyword . "primary"))) 56 | proc) 57 | (should (equal (car (citeproc-render-bib proc 'plain)) 58 | '("Doe, Jane. 1972a. The Second 1972 Jane Doe Book.\n\n———. 1972b. The Second Book Title.\n\n———. 1972c. The Third 1972 Jane Doe Book.\n\nSmith, Peter. 1952. The Book Title." 59 | "Doe, Jane. 1972c. The Third 1972 Jane Doe Book.\n\nDoe, John. 2001. “The Title.” The Mind Scientific 103 (1): 45–58.\n\nSmith, Peter. 1952. The Book Title."))))) 60 | 61 | (ert-deftest citeproc-test-int-sb/single-filter () 62 | (let* ((ig (citeproc-itemgetter-from-csl-json 63 | (concat citeproc-test-int-root-dir "etc/subbibs.json"))) 64 | (lg (citeproc-locale-getter-from-dir 65 | (concat citeproc-test-int-root-dir "locales"))) 66 | (proc (citeproc-create 67 | (concat citeproc-test-int-root-dir "etc/chicago-author-date.csl") ig lg))) 68 | (citeproc-add-uncited '("doe1972" "doe1972b" "doe1972c") proc) 69 | ;; Single empty filter 70 | (citeproc-add-subbib-filters '(nil) proc) 71 | (should (equal (car (citeproc-render-bib proc 'plain)) 72 | '("Doe, Jane. 1972a. The Second 1972 Jane Doe Book.\n\n———. 1972b. The Second Book Title.\n\n———. 1972c. The Third 1972 Jane Doe Book."))) 73 | (citeproc-clear proc) 74 | ;; Single non-empty filter 75 | (citeproc-add-uncited '("doe1972" "doe1972b" "doe1972c" "doe2001") proc) 76 | (citeproc-add-subbib-filters 77 | '(((type . "article-journal"))) 78 | proc) 79 | (should (equal (car (citeproc-render-bib proc 'plain)) 80 | '("Doe, John. 2001. “The Title.” The Mind Scientific 103 (1): 45–58."))))) 81 | 82 | (provide 'citeproc-test-int-subbibs) 83 | 84 | ;;; citeproc-test-int-subbibs.el ends here 85 | -------------------------------------------------------------------------------- /citeproc-itemdata.el: -------------------------------------------------------------------------------- 1 | ;;; citeproc-itemdata.el --- represent and access bibliography items -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright (C) 2017 András Simonyi 4 | 5 | ;; Author: András Simonyi 6 | 7 | ;; This program is free software; you can redistribute it and/or modify 8 | ;; it under the terms of the GNU General Public License as published by 9 | ;; the Free Software Foundation, either version 3 of the License, or 10 | ;; (at your option) any later version. 11 | 12 | ;; This program is distributed in the hope that it will be useful, 13 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | ;; GNU General Public License for more details. 16 | 17 | ;; You should have received a copy of the GNU General Public License 18 | ;; along with this program. If not, see . 19 | 20 | ;; This file is not part of GNU Emacs. 21 | 22 | ;;; Commentary: 23 | 24 | ;; Structure type and functions to handle data about bibliography items. 25 | 26 | ;;; Code: 27 | 28 | (require 'citeproc-rt) 29 | (require 'citeproc-context) 30 | 31 | (cl-defstruct (citeproc-itemdata (:constructor citeproc-itemdata-create)) 32 | "Struct for storing bibliography item data. 33 | VARVALS is an alist containg variable-name symbols as keys and 34 | their values for the item as values, 35 | RAWCITE is the cached cite of the item in internal rich-text 36 | format, 37 | RC-UPTODATE is t iff the RAWCITE field is up-to-date, 38 | RAWBIBITEM is the cached bibliograhy item in internal rich-text 39 | format. 40 | SORT-KEY is the bibliography sort-key of the item, 41 | OCCURRED-BEFORE is used during bibliography generation to 42 | indicate whether the item was referred to earlier. If the first 43 | occurrence is in a note then the actual value is the 44 | note-number, 45 | DISAMB-POS contains the position on which cite disambiguation is 46 | based. Possible values are 'first, 'ibid and 'subsequent, 47 | SUBBIB-NOS is a list of numeric indexes of sub-bibliographies 48 | in which the item occurs, 49 | UNCITED is t iff the item has no associated citation." 50 | varvals rawcite rawbibitem rc-uptodate sort-key occurred-before 51 | disamb-pos subbib-nos uncited) 52 | 53 | (defun citeproc-itd-getvar (itd var) 54 | "Return itemdata ITD's value for VAR ." 55 | (alist-get var (citeproc-itemdata-varvals itd))) 56 | 57 | (defun citeproc-itd-setvar (itd var val) 58 | "Set itemdata ITD's value for VAR to VAL." 59 | (setf (alist-get var (citeproc-itemdata-varvals itd) nil t) val 60 | (citeproc-itemdata-rc-uptodate itd) nil)) 61 | 62 | (defun citeproc-itd-rt-cite (itd style) 63 | "Return the rich-text cite of itemdata ITD using STYLE." 64 | (if (citeproc-itemdata-rc-uptodate itd) 65 | (citeproc-itemdata-rawcite itd) 66 | (let ((rc (citeproc-render-varlist-in-rt 67 | (cons (cons 'position (citeproc-itemdata-disamb-pos itd)) 68 | (citeproc-itemdata-varvals itd)) 69 | style 70 | 'cite 'display 'no-links t))) 71 | (setf (citeproc-itemdata-rawcite itd) rc 72 | (citeproc-itemdata-rc-uptodate itd) t) 73 | rc))) 74 | 75 | (defun citeproc-itd-plain-cite (itd style) 76 | "Return the plain text cite of itemdata ITD using STYLE." 77 | (citeproc-rt-to-plain (citeproc-itd-rt-cite itd style))) 78 | 79 | (defun citeproc-itd-namevars (itd style) 80 | "Rendered namevars in the cite of itemdata ITD using STYLE." 81 | (citeproc-rt-rendered-name-vars (citeproc-itd-rt-cite itd style))) 82 | 83 | (defun citeproc-itd-nameids (itd style) 84 | "Rendered name ids in the cite of itemdata ITD using STYLE." 85 | (citeproc-rt-rendered-name-ids (citeproc-itd-rt-cite itd style))) 86 | 87 | (defun citeproc-itd-update-disamb-pos (itd pos) 88 | "Update the highest position of ITD with position POS." 89 | (let ((old (citeproc-itemdata-disamb-pos itd))) 90 | (unless (eq old 'subsequent) 91 | (let ((new (pcase pos 92 | ('first 'first) 93 | ((or 'ibid 'ibid-with-locator) 'ibid) 94 | (_ 'subsequent)))) 95 | (setf (citeproc-itemdata-disamb-pos itd) 96 | (cond ((memq old '(nil first)) new) 97 | ((eq new 'subsequent) 'subsequent) 98 | (t 'ibid))))))) 99 | 100 | (provide 'citeproc-itemdata) 101 | 102 | ;;; citeproc-itemdata.el ends here 103 | -------------------------------------------------------------------------------- /citeproc-term.el: -------------------------------------------------------------------------------- 1 | ;;; citeproc-term.el --- functions for term localization -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright (C) 2017 András Simonyi 4 | 5 | ;; Author: András Simonyi 6 | 7 | ;; This program is free software; you can redistribute it and/or modify 8 | ;; it under the terms of the GNU General Public License as published by 9 | ;; the Free Software Foundation, either version 3 of the License, or 10 | ;; (at your option) any later version. 11 | 12 | ;; This program is distributed in the hope that it will be useful, 13 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | ;; GNU General Public License for more details. 16 | 17 | ;; You should have received a copy of the GNU General Public License 18 | ;; along with this program. If not, see . 19 | 20 | ;; This file is not part of GNU Emacs. 21 | 22 | ;;; Commentary: 23 | 24 | ;; Functions for localizing the terms of a CSL style according to a locale. 25 | 26 | ;;; Code: 27 | 28 | (require 'dash) 29 | (require 'cl-lib) 30 | (require 'let-alist) 31 | 32 | (require 'citeproc-lib) 33 | (require 'citeproc-s) 34 | 35 | (cl-defstruct (citeproc-term (:constructor citeproc-term--create)) 36 | "A struct representing a localized term." 37 | (name nil) (form nil) (number nil) (gender nil) (gender-form nil) 38 | (match nil) (text nil)) 39 | 40 | (defun citeproc-term--compare (t1 t2) 41 | "Compare terms T1 and T2. 42 | The comparison is based on the term fields except the last one, 43 | and relies on the alphabetical ordering of fields' string 44 | content (see the function `citeproc-lib-s-content'). Return 1, -1 45 | or 0 iff T1 precedes, succeeds or is equal according to the 46 | ordering." 47 | (cond ((not t2) 1) 48 | ((not t1) -1) 49 | (t (let ((idx 1) 50 | (result 0)) 51 | (while (and (= result 0) (< idx 7)) 52 | (let ((s1 (citeproc-s-content (aref t1 idx))) 53 | (s2 (citeproc-s-content (aref t2 idx)))) 54 | (cond ((string< s1 s2) (setq result 1)) 55 | ((string> s1 s2) (setq result -1)))) 56 | (cl-incf idx)) result)))) 57 | 58 | (defun citeproc-term-list--sort (tl) 59 | "Sort termlist TL in place using `citeproc-term--compare'." 60 | (cl-sort tl (lambda (x y) (> (citeproc-term--compare x y) -1)))) 61 | 62 | (defun citeproc-term-list-update (tl1 tl2 &optional sorted-input) 63 | "Return a term list which is TL1 updated with term list TL2. 64 | TL1 and TL2 are list of citeproc-term structs. The order of terms 65 | in the returned term list is undetermined. If the optional 66 | SORTED-INPUT is non-nil then the term lists are supposed to be 67 | already sorted according to `citeproc-term--compare', otherwise 68 | they are sorted in-place." 69 | (let (result) 70 | (unless sorted-input 71 | (setq tl1 (citeproc-term-list--sort tl1) 72 | tl2 (citeproc-term-list--sort tl2))) 73 | (while (or tl1 tl2) 74 | (let* ((t1 (car tl1)) 75 | (t2 (car tl2)) 76 | (cmp (citeproc-term--compare t1 t2))) 77 | (cond ((= cmp 1) (push t1 result) (pop tl1)) 78 | ((= cmp -1) (push t2 result) (pop tl2)) 79 | (t (push t2 result) (pop tl1) (pop tl2))))) 80 | result)) 81 | 82 | (defun citeproc-term--from-xml-frag (frag) 83 | "Transform xml FRAG representing a term into a citeproc-term struct." 84 | (let-alist (car frag) 85 | (-let* ((.form (or .form "long")) 86 | (term (citeproc-term--create 87 | :name .name 88 | :form (citeproc-lib-intern .form) 89 | :gender (citeproc-lib-intern .gender) 90 | :match (citeproc-lib-intern .match) 91 | :gender-form (citeproc-lib-intern .gender-form)))) 92 | (if (= (length frag) 2) 93 | (progn 94 | (setf (citeproc-term-text term) (cadr frag)) 95 | (list term)) 96 | (setf (citeproc-term-text term) (cl-caddr (cadr frag))) 97 | (setf (citeproc-term-number term) 'single) 98 | (let ((multi-term (copy-citeproc-term term))) 99 | (setf (citeproc-term-text multi-term) (cl-caddr (cl-caddr frag))) 100 | (setf (citeproc-term-number multi-term) 'multiple) 101 | (list term multi-term)))))) 102 | 103 | (defun citeproc-term-text-from-terms (term terms) 104 | "Return the first text associated with TERM in TERMS. 105 | Return nil if TERM is not in TERMS." 106 | (-if-let (match (--first (string= term (citeproc-term-name it)) 107 | terms)) 108 | (citeproc-term-text match) 109 | nil)) 110 | 111 | (provide 'citeproc-term) 112 | 113 | ;;; citeproc-term.el ends here 114 | -------------------------------------------------------------------------------- /test/biblatex_csl/incollection.txt: -------------------------------------------------------------------------------- 1 | --- 2 | @comment{adapted from http://mirrors.ctan.org/macros/latex/contrib/biblatex/doc/examples/biblatex-examples.bib} 3 | 4 | @string{hup = {Harvard University Press}} 5 | 6 | @incollection{brandt, 7 | Annotation = {An incollection entry with a series and a number. Note the format of the printed name and compare the useprefix option in the options field as well as vangennep. Also note the indextitle, and indexsorttitle fields}, 8 | Author = {von Brandt, Ahasver and Hoffmann, Erich}, 9 | Booktitle = {Europa im Hoch- und Spätmittelalter}, 10 | Date = 1987, 11 | Editor = {Seibt, Ferdinand}, 12 | Indexsorttitle = {Nordischen Lander von der Mitte des 11. Jahrhunderts bis 1448}, 13 | Indextitle = {Nordischen Länder von der Mitte des 11.~Jahrhunderts bis 1448, Die}, 14 | Location = {Stuttgart}, 15 | Number = 2, 16 | Options = {useprefix=false}, 17 | Pages = {884-917}, 18 | Publisher = {Klett-Cotta}, 19 | Series = {Handbuch der europäischen Geschichte}, 20 | Shorttitle = {Die nordischen Länder}, 21 | Title = {Die nordischen Länder von der Mitte des 11. Jahrhunderts bis 1448}, 22 | Langid = {german}} 23 | 24 | @incollection{hyman, 25 | Annotation = {An incollection entry with a series and number field}, 26 | Author = {Hyman, Arthur}, 27 | Booktitle = {Studies in {Aristotle}}, 28 | Date = 1981, 29 | Editor = {O'Meara, Dominic J.}, 30 | Indextitle = {Aristotle's Theory of the Intellect}, 31 | Keywords = {secondary}, 32 | Location = {Washington, D.C.}, 33 | Number = 9, 34 | Pages = {161-191}, 35 | Publisher = {The Catholic University of America Press}, 36 | Series = {Studies in Philosophy and the History of Philosophy}, 37 | Shorttitle = {Aristotle's Theory of the Intellect}, 38 | Title = {Aristotle's Theory of the Intellect and its Interpretation by {Averroes}}} 39 | 40 | @incollection{pines, 41 | Annotation = {A typical incollection entry. Note the indextitle field}, 42 | Author = {Pines, Shlomo}, 43 | Booktitle = {Studies in Medieval {Jewish} History and Literature}, 44 | Date = 1979, 45 | Editor = {Twersky, Isadore}, 46 | Indextitle = {Limitations of Human Knowledge According to Al-Farabi, ibn Bajja, and Maimonides, The}, 47 | Keywords = {secondary}, 48 | Location = {Cambridge, Mass.}, 49 | Pages = {82-109}, 50 | Publisher = hup, 51 | Shorttitle = {Limitations of Human Knowledge}, 52 | Title = {The Limitations of Human Knowledge According to {Al-Farabi}, {ibn Bajja}, and {Maimonides}}} 53 | --- 54 | - annote: An incollection entry with a series and a number. Note the 55 | format of the printed name and compare the useprefix option in the 56 | options field as well as vangennep. Also note the indextitle, and 57 | indexsorttitle fields 58 | author: 59 | - non-dropping-particle: von 60 | family: Brandt 61 | given: Ahasver 62 | - family: Hoffmann 63 | given: Erich 64 | blt-type: incollection 65 | collection-number: 2 66 | collection-title: Handbuch der europäischen Geschichte 67 | container-title: Europa im Hoch- und Spätmittelalter 68 | editor: 69 | - family: Seibt 70 | given: Ferdinand 71 | id: brandt 72 | issued: 1987 73 | language: de-DE 74 | page: 884-917 75 | publisher: Klett-Cotta 76 | publisher-place: Stuttgart 77 | title: Die nordischen Länder von der Mitte des 11. Jahrhunderts bis 78 | 1448 79 | title-short: Die nordischen Länder 80 | type: chapter 81 | - annote: An incollection entry with a series and number field 82 | author: 83 | - family: Hyman 84 | given: Arthur 85 | blt-type: incollection 86 | collection-number: 9 87 | collection-title: Studies in philosophy and the history of philosophy 88 | container-title: Studies in Aristotle 89 | editor: 90 | - family: O'Meara 91 | given: Dominic J. 92 | id: hyman 93 | issued: 1981 94 | keyword: secondary 95 | page: 161-191 96 | publisher: The Catholic University of America Press 97 | publisher-place: Washington, D.C. 98 | title: Aristotle's theory of the intellect and its interpretation by Averroes 99 | title-short: Aristotle's theory of the intellect 100 | type: chapter 101 | - annote: A typical incollection entry. Note the indextitle field 102 | author: 103 | - family: Pines 104 | given: Shlomo 105 | blt-type: incollection 106 | container-title: Studies in medieval Jewish history and literature 107 | editor: 108 | - family: Twersky 109 | given: Isadore 110 | id: pines 111 | issued: 1979 112 | keyword: secondary 113 | page: 82-109 114 | publisher: Harvard University Press 115 | publisher-place: Cambridge, Mass. 116 | title: The limitations of human knowledge according to Al-Farabi, ibn 117 | Bajja, and Maimonides 118 | title-short: Limitations of human knowledge 119 | type: chapter 120 | -------------------------------------------------------------------------------- /test/citeproc-test-int-biblatex.el: -------------------------------------------------------------------------------- 1 | ;;; citeproc-test-int-biblatex.el --- biblatex tests -*- lexical-binding: t; -*- 2 | 3 | (require 'ert) 4 | (require 'yaml) 5 | (require 'string-inflection) 6 | (require 'ht) 7 | (require 'parsebib) 8 | 9 | (require 'citeproc-biblatex) 10 | (require 'citeproc-lib) 11 | 12 | (defun citeproc-test-blt--parse (file) 13 | "Parse a biblatex->CSL test file. 14 | Returns a (BLT . CSL) pair where BLT is the `parsebib'-parsed 15 | form of the biblatex part and CSL is the `yaml'-parsed form of 16 | the CSL part." 17 | (let (blt csl blt-start blt-end blt-string) 18 | (with-temp-buffer 19 | (insert-file-contents file) 20 | (goto-char 1) 21 | (re-search-forward "---" nil) 22 | (forward-line) 23 | (move-beginning-of-line nil) 24 | (setq blt-start (point)) 25 | (re-search-forward "---" nil) 26 | (forward-line -1) 27 | (move-end-of-line nil) 28 | (setq blt-end (point) 29 | blt-string (buffer-substring-no-properties blt-start blt-end)) 30 | (with-temp-buffer 31 | (insert blt-string) 32 | (goto-char 1) 33 | (setq blt (ht->alist 34 | (car (parsebib-parse-bib-buffer :expand-strings t :inheritance t))))) 35 | (forward-line 2) 36 | (move-beginning-of-line nil) 37 | (setq csl (yaml-parse-string 38 | (buffer-substring-no-properties (point) (point-max)) 39 | :object-type 'alist 40 | :sequence-type 'list)) 41 | (cons blt csl)))) 42 | 43 | (defun citeproc-test-blt--sort-alist (alist) 44 | "Sort alist A according to key alphabetic order." 45 | (sort alist (lambda (x y) (string< (car x) (car y))))) 46 | 47 | (defun citeproc-test-blt--sort-nparts (csl-entry) 48 | "Sort the name-parts in a CSL entry." 49 | (dolist (kv csl-entry) 50 | (when (memq (car kv) citeproc--name-vars) 51 | (let* ((names (cdr kv)) 52 | (sorted-names (mapcar #'citeproc-test-blt--sort-alist names))) 53 | (setf (cdr kv) sorted-names)))) 54 | csl-entry) 55 | 56 | (defun citeproc-test-blt--simplify-dates (csl-entry) 57 | "Convert date entries to readable, simple fields" 58 | (dolist (kv csl-entry) 59 | (when (memq (car kv) citeproc--date-vars) 60 | (let* ((interval-date-parts (cdadr kv)) 61 | (simplified-int-parts 62 | (mapconcat 63 | (lambda (int-part) 64 | (mapconcat 65 | (lambda (x) 66 | (let ((str (number-to-string x))) 67 | (if (= (length str) 1) 68 | (concat "0" str) 69 | str))) 70 | int-part "-")) 71 | interval-date-parts "/")) ) 72 | (setf (cdr kv) simplified-int-parts)))) 73 | csl-entry) 74 | 75 | (defun citeproc-test-blt--stringify (alist) 76 | "Convert all numerical values to strings." 77 | (dolist (kv alist) 78 | (when (numberp (cdr kv)) 79 | (setf (cdr kv) (number-to-string (cdr kv))))) 80 | alist) 81 | 82 | (defun citeproc-test-blt--normalize-csl-entries (entries) 83 | "Normalize a list of csl entries. 84 | Performs the following steps: 85 | - sorts the entries according to the id field, 86 | - sorts the kv pairs according to key inside entries, 87 | - converts numerical values to strings, 88 | - sorts name-parts according to keys. 89 | All sorts are alphanumerically increasing." 90 | (let* ((stringified (mapcar #'citeproc-test-blt--stringify entries)) 91 | (id-sorted (sort stringified 92 | (lambda (x y) 93 | (string< (alist-get 'id x) 94 | (alist-get 'id y))))) 95 | (internally-sorted (mapcar #'citeproc-test-blt--sort-alist id-sorted))) 96 | (mapcar #'citeproc-test-blt--sort-nparts internally-sorted))) 97 | 98 | (defun citeproc-test-blt--output (blt) 99 | "Generate normalized output from biblatex parse BLT." 100 | (let* ((processed (mapcar (lambda (x) 101 | (let ((csl-entry (citeproc-blt-entry-to-csl (cdr x) t))) 102 | (push (cons 'id (car x)) csl-entry) 103 | (citeproc-test-blt--simplify-dates 104 | csl-entry))) 105 | blt))) 106 | (citeproc-test-blt--normalize-csl-entries processed))) 107 | 108 | (defun citeproc-test-blt-create-from-file (file) 109 | "Create an ERT test from a blt-csl mapping file." 110 | (pcase-let* ((`(,blt . ,csl) 111 | (citeproc-test-blt--parse file)) 112 | (expected (citeproc-test-blt--normalize-csl-entries csl)) 113 | (file-name (f-filename file)) 114 | (test-name (intern 115 | (concat "citeproc-int-blt-" 116 | (string-inflection-kebab-case-function 117 | (substring file-name 0 -4)))))) 118 | (eval `(ert-deftest ,test-name () 119 | (should (equal 120 | ',expected 121 | (citeproc-test-blt--output ',blt))))))) 122 | 123 | (defun citeproc-test-blt-create-from-dir (dir) 124 | "Create all blt-csl mapping tests from DIR." 125 | (dolist (test-file (f-glob (concat dir "/*.txt"))) 126 | (citeproc-test-blt-create-from-file test-file))) 127 | 128 | (citeproc-test-blt-create-from-dir "./test/biblatex_csl") 129 | 130 | (provide 'citeproc-test-int-biblatex) 131 | 132 | ;;; citeproc-test-int-biblatex.el ends here 133 | -------------------------------------------------------------------------------- /citeproc-choose.el: -------------------------------------------------------------------------------- 1 | ;; citeproc-choose.el --- conditionally rendered CSL elements -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright (C) 2017 András Simonyi 4 | 5 | ;; Author: András Simonyi 6 | 7 | ;; This program is free software; you can redistribute it and/or modify 8 | ;; it under the terms of the GNU General Public License as published by 9 | ;; the Free Software Foundation, either version 3 of the License, or 10 | ;; (at your option) any later version. 11 | 12 | ;; This program is distributed in the hope that it will be useful, 13 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | ;; GNU General Public License for more details. 16 | 17 | ;; You should have received a copy of the GNU General Public License 18 | ;; along with this program. If not, see . 19 | 20 | ;; This file is not part of GNU Emacs. 21 | 22 | ;;; Commentary: 23 | 24 | ;; CSL supports conditional rendering via the cs:choose rendering element, which 25 | ;; can contain cs:if, cs:else-if and cs:else elements as children. This file 26 | ;; contains functions corresponding to all these elements with some auxiliary 27 | ;; functions. 28 | 29 | ;; In order to support conditional rendering by cs:choose, the functions 30 | ;; corresponding to cs:if, cs:else-if and cs:else (`citeproc--if', 31 | ;; `citeproc--else-if', `citeproc--else') return the generalized boolean value 32 | ;; of their condition in addition to their rendered content in the form of a 33 | ;; (BOOLEAN . CONTENT) pair. 34 | 35 | ;;; Code: 36 | 37 | (require 's) 38 | 39 | (require 'citeproc-lib) 40 | (require 'citeproc-context) 41 | (require 'citeproc-date) 42 | 43 | (defun citeproc-choose-eval-conditions (attrs context) 44 | "Eval (possibly complex) boolean conditions in ATTRS." 45 | (-let* ((conditions (citeproc-choose--elementary-conditions 46 | (--remove (eq (car it) 'match) attrs))) 47 | (match (or (alist-get 'match attrs) "all")) 48 | (values (--map (citeproc-choose--eval-elementary-condition (car it) 49 | (intern (cdr it)) 50 | context) 51 | conditions))) 52 | (pcase match 53 | ("all" (--all? it values)) 54 | ("any" (--any? it values)) 55 | ("none" (--none? it values))))) 56 | 57 | (defun citeproc-choose--elementary-conditions (attrs) 58 | "Expand complex conditions in ATTRS into elementary ones. 59 | Return a list of elementary (CONDITION-TYPE . PARAM) pairs." 60 | (cl-mapcan (lambda (x) 61 | (--map (cons (car x) it) 62 | (s-split " " (cdr x)))) 63 | attrs)) 64 | 65 | (defun citeproc-choose--eval-elementary-condition (type param context) 66 | "Evaluate an elementary choose condition of TYPE with PARAM. 67 | TYPE is one of the symbols `variable', `type', `locator', 68 | `is-numeric', `is-uncertain-date', `position' and `disambiguate'. 69 | Return the result of evaluation, which is a generalized boolean." 70 | (pcase type 71 | ('variable (citeproc-var-value param context)) 72 | ('type (string= param (citeproc-var-value 'type context))) 73 | ('locator (string= param (citeproc-var-value 'label context))) 74 | ('is-numeric (let ((val (citeproc-var-value param context))) 75 | (citeproc-lib-numeric-p val))) 76 | ;; We return t iff the first date is uncertain. A more complicated alternative 77 | ;; would be to test the second date of date ranges as well. 78 | ('is-uncertain-date (-when-let (dates (citeproc-var-value param context)) 79 | (citeproc-date-circa (car dates)))) 80 | ('position (and (eq (citeproc-context-mode context) 'cite) 81 | (or (and (eq param 'near-note) (citeproc-var-value 'near-note context)) 82 | (let ((pos (citeproc-var-value 'position context))) 83 | (or (eq param pos) 84 | (and (eq param 'subsequent) 85 | (or (eq pos 'ibid) (eq pos 'ibid-with-locator))) 86 | (and (eq param 'ibid) 87 | (eq pos 'ibid-with-locator))))))) 88 | ('disambiguate (citeproc-var-value 'disambiguate context)))) 89 | 90 | (defmacro citeproc--choose (_attrs _context &rest body) 91 | "Return the content of the first element in BODY with t boolean value. 92 | Return the empty (nil . `text-only') content if there is no such 93 | element." 94 | `(let ((first-true 95 | (--first (car it) (list ,@body)))) 96 | (if first-true 97 | (cdr first-true) 98 | (cons nil (quote text-only))))) 99 | 100 | (defmacro citeproc--if (attrs context &rest body) 101 | "If conditions in ATTRS eval to t return t with rendered BODY. 102 | Return nil otherwise." 103 | `(if (citeproc-choose-eval-conditions ,attrs ,context) 104 | (cons t (citeproc-lib-add-splice-tag 105 | (citeproc-lib-splice-into (list ,@body) 'splice) 106 | 'splice)) 107 | nil)) 108 | 109 | (defalias 'citeproc--else-if 'citeproc--if) 110 | 111 | (defun citeproc--else (_attrs _context &rest body) 112 | "Always return t boolean plus rendered BODY" 113 | (let ((spliced-body (citeproc-lib-splice-into body 'splice))) 114 | (cons t (citeproc-lib-add-splice-tag spliced-body 'splice)))) 115 | 116 | (provide 'citeproc-choose) 117 | 118 | ;;; citeproc-choose.el ends here 119 | -------------------------------------------------------------------------------- /test/biblatex_csl/inbook.txt: -------------------------------------------------------------------------------- 1 | --- 2 | @string{dtv = {Deutscher Taschenbuch-Verlag}} 3 | 4 | @inbook{kant:kpv, 5 | Annotation = {An edition of Kant's Collected Works, volume five. This is an inbook entry which explicitly refers to the Critique of Practical Reason only, not to the entire fifth volume. Note the author and bookauthor fields in the database file. By default, the bookauthor is omitted if the values of the author and bookauthor fields are identical}, 6 | Author = {Kant, Immanuel}, 7 | Bookauthor = {Kant, Immanuel}, 8 | Booktitle = {Kritik der praktischen Vernunft. Kritik der Urtheilskraft}, 9 | Date = 1968, 10 | Location = {Berlin}, 11 | Maintitle = {Kants Werke. Akademie Textausgabe}, 12 | Pages = {1-163}, 13 | Publisher = {Walter de Gruyter}, 14 | Shorthand = {KpV}, 15 | Shorttitle = {Kritik der praktischen Vernunft}, 16 | Title = {Kritik der praktischen Vernunft}, 17 | Volume = 5, 18 | Langid = {german}} 19 | 20 | @inbook{kant:ku, 21 | Annotation = {An edition of Kant's Collected Works, volume five. This is an inbook entry which explicitly refers to the Critique of Judgment only, not to the entire fifth volume}, 22 | Author = {Kant, Immanuel}, 23 | Bookauthor = {Kant, Immanuel}, 24 | Booktitle = {Kritik der praktischen Vernunft. Kritik der Urtheilskraft}, 25 | Date = 1968, 26 | Location = {Berlin}, 27 | Maintitle = {Kants Werke. Akademie Textausgabe}, 28 | Pages = {165-485}, 29 | Publisher = {Walter de Gruyter}, 30 | Shorthand = {KU}, 31 | Title = {Kritik der Urtheilskraft}, 32 | Langid = {german}, 33 | Volume = 5} 34 | 35 | @inbook{nietzsche:historie, 36 | Annotation = {A single essay from the critical edition of Nietzsche's works. This inbook entry explicitly refers to an essay found in the first volume. Note the title, booktitle, and maintitle fields. Also note the sorttitle and sortyear fields. We want this entry to be listed after the entry referring to the entire first volume}, 37 | Author = {Nietzsche, Friedrich}, 38 | Bookauthor = {Nietzsche, Friedrich}, 39 | Booktitle = {Die Geburt der Tragödie. Unzeitgemäße Betrachtungen I--IV. Nachgelassene Schriften 1870--1973}, 40 | Date = 1988, 41 | Editor = {Colli, Giorgio and Montinari, Mazzino}, 42 | Hyphenation = {german}, 43 | Indexsorttitle = {Vom Nutzen und Nachtheil der Historie fur das Leben}, 44 | Indextitle = {Vom Nutzen und Nachtheil der Historie für das Leben}, 45 | Location = {München and Berlin and New York}, 46 | Mainsubtitle = {Kritische Studienausgabe}, 47 | Maintitle = {Sämtliche Werke}, 48 | Pages = {243-334}, 49 | Publisher = dtv # { and Walter de Gruyter}, 50 | Shorttitle = {Vom Nutzen und Nachtheil der Historie}, 51 | Sorttitle = {Werke-01-243}, 52 | Sortyear = {1988-2}, 53 | Subtitle = {Vom Nutzen und Nachtheil der Historie für das Leben}, 54 | Title = {Unzeitgemässe Betrachtungen. Zweites Stück}, 55 | Volume = 1, 56 | Langid = {german}} 57 | --- 58 | - annote: An edition of Kant's Collected Works, volume five. This is 59 | an inbook entry which explicitly refers to the Critique of 60 | Practical Reason only, not to the entire fifth volume. Note the 61 | author and bookauthor fields in the database file. By default, the 62 | bookauthor is omitted if the values of the author and bookauthor 63 | fields are identical 64 | author: 65 | - family: Kant 66 | given: Immanuel 67 | blt-type: inbook 68 | container-author: 69 | - family: Kant 70 | given: Immanuel 71 | container-title: Kants Werke. Akademie Textausgabe 72 | id: "kant:kpv" 73 | issued: 1968 74 | language: de-DE 75 | page: 1-163 76 | publisher: Walter de Gruyter 77 | publisher-place: Berlin 78 | title: Kritik der praktischen Vernunft 79 | title-short: Kritik der praktischen Vernunft 80 | type: chapter 81 | volume: 5 82 | volume-title: Kritik der praktischen Vernunft. Kritik der 83 | Urtheilskraft 84 | - annote: An edition of Kant's Collected Works, volume five. This is 85 | an inbook entry which explicitly refers to the Critique of 86 | Judgment only, not to the entire fifth volume 87 | author: 88 | - family: Kant 89 | given: Immanuel 90 | blt-type: inbook 91 | container-author: 92 | - family: Kant 93 | given: Immanuel 94 | container-title: Kants Werke. Akademie Textausgabe 95 | id: "kant:ku" 96 | issued: 1968 97 | language: de-DE 98 | page: 165-485 99 | publisher: Walter de Gruyter 100 | publisher-place: Berlin 101 | title: Kritik der Urtheilskraft 102 | type: chapter 103 | volume: 5 104 | volume-title: Kritik der praktischen Vernunft. Kritik der 105 | Urtheilskraft 106 | - annote: A single essay from the critical edition of Nietzsche's works. 107 | This inbook entry explicitly refers to an essay found in the first 108 | volume. Note the title, booktitle, and maintitle fields. Also note 109 | the sorttitle and sortyear fields. We want this entry to be listed 110 | after the entry referring to the entire first volume 111 | author: 112 | - family: Nietzsche 113 | given: Friedrich 114 | blt-type: inbook 115 | container-author: 116 | - family: Nietzsche 117 | given: Friedrich 118 | container-title: "Sämtliche Werke: Kritische Studienausgabe" 119 | editor: 120 | - family: Colli 121 | given: Giorgio 122 | - family: Montinari 123 | given: Mazzino 124 | id: "nietzsche:historie" 125 | issued: 1988 126 | language: de-DE 127 | page: 243-334 128 | publisher: Deutscher Taschenbuch-Verlag and Walter de Gruyter 129 | publisher-place: München and Berlin and New York 130 | title: "Unzeitgemässe Betrachtungen. Zweites Stück: Vom Nutzen und 131 | Nachtheil der Historie für das Leben" 132 | title-short: Vom Nutzen und Nachtheil der Historie 133 | type: chapter 134 | volume: 1 135 | volume-title: Die Geburt der Tragödie. Unzeitgemäße Betrachtungen 136 | I–IV. Nachgelassene Schriften 1870–1973 137 | -------------------------------------------------------------------------------- /test/biblatex_csl/report.txt: -------------------------------------------------------------------------------- 1 | --- 2 | @report{chiu, 3 | Annotation = {This is a report entry for a research report. Note the format of the type field in the database file which uses a localization key. The number of the report is given in the number field. Also note the sorttitle and indextitle fields}, 4 | Author = {Chiu, Willy W. and Chow, We Min}, 5 | Date = 1978, 6 | Indextitle = {Hybrid Hierarchical Model, A}, 7 | Institution = {IBM}, 8 | Number = {RC-6947}, 9 | Sorttitle = {Hybrid Hierarchical Model of a Multiple Virtual Storage (MVS) Operating System}, 10 | Title = {A Hybrid Hierarchical Model of a {Multiple Virtual Storage} ({MVS}) Operating System}, 11 | Type = {resreport}} 12 | 13 | @report{padhye, 14 | Annotation = {This is a report entry for a technical report. Note the format of the type field in the database file which uses a localization key. The number of the report is given in the number field. Also note the sorttitle and indextitle fields}, 15 | Author = {Padhye, Jitendra and Firoiu, Victor and Towsley, Don}, 16 | Date = 1999, 17 | File = {ftp://gaia.cs.umass.edu/pub/Padhey99-markov.ps}, 18 | Indextitle = {Stochastic Model of TCP Reno Congestion Avoidance and Control, A}, 19 | Institution = {University of Massachusetts}, 20 | Location = {Amherst, Mass.}, 21 | Number = {99-02}, 22 | Sorttitle = {A Stochastic Model of TCP Reno Congestion Avoidance and Control}, 23 | Title = {A Stochastic Model of {TCP Reno} Congestion Avoidance and Control}, 24 | Type = {techreport}, 25 | Abstract = {The steady state performance of a bulk transfer TCP flow 26 | (i.e., a flow with a large amount of data to send, such as FTP 27 | transfers) may be characterized by three quantities. The first 28 | is the send rate, which is the amount of data sent by the 29 | sender in unit time. The second is the throughput, which is 30 | the amount of data received by the receiver in unit time. Note 31 | that the throughput will always be less than or equal to the 32 | send rate due to losses. Finally, the number of non-duplicate 33 | packets received by the receiver in unit time gives us the 34 | goodput of the connection. The goodput is always less than or 35 | equal to the throughput, since the receiver may receive two 36 | copies of the same packet due to retransmissions by the 37 | sender. In a previous paper, we presented a simple model for 38 | predicting the steady state send rate of a bulk transfer TCP 39 | flow as a function of loss rate and round trip time. In this 40 | paper, we extend that work in two ways. First, we analyze the 41 | performance of bulk transfer TCP flows using more precise, 42 | stochastic analysis. Second, we build upon the previous 43 | analysis to provide both an approximate formula as well as a 44 | more accurate stochastic model for the steady state throughput 45 | of a bulk transfer TCP flow.}} 46 | --- 47 | - annote: This is a report entry for a research report. Note the format 48 | of the type field in the database file which uses a localization 49 | key. The number of the report is given in the number field. Also 50 | note the sorttitle and indextitle fields 51 | author: 52 | - family: Chiu 53 | given: Willy W. 54 | - family: Chow 55 | given: We Min 56 | blt-type: report 57 | genre: research report 58 | id: chiu 59 | issued: 1978 60 | number: RC-6947 61 | publisher: IBM 62 | title: A hybrid hierarchical model of a Multiple Virtual Storage (MVS) operating system 63 | type: report 64 | - abstract: The steady state performance of a bulk transfer TCP flow 65 | (i.e., a flow with a large amount of data to send, such as FTP 66 | transfers) may be characterized by three quantities. The first is 67 | the send rate, which is the amount of data sent by the sender in 68 | unit time. The second is the throughput, which is the amount of data 69 | received by the receiver in unit time. Note that the throughput will 70 | always be less than or equal to the send rate due to losses. 71 | Finally, the number of non-duplicate packets received by the 72 | receiver in unit time gives us the goodput of the connection. The 73 | goodput is always less than or equal to the throughput, since the 74 | receiver may receive two copies of the same packet due to 75 | retransmissions by the sender. In a previous paper, we presented a 76 | simple model for predicting the steady state send rate of a bulk 77 | transfer TCP flow as a function of loss rate and round trip time. In 78 | this paper, we extend that work in two ways. First, we analyze the 79 | performance of bulk transfer TCP flows using more precise, 80 | stochastic analysis. Second, we build upon the previous analysis to 81 | provide both an approximate formula as well as a more accurate 82 | stochastic model for the steady state throughput of a bulk transfer 83 | TCP flow. 84 | annote: This is a report entry for a technical report. Note the format 85 | of the type field in the database file which uses a localization 86 | key. The number of the report is given in the number field. Also 87 | note the sorttitle and indextitle fields 88 | author: 89 | - family: Padhye 90 | given: Jitendra 91 | - family: Firoiu 92 | given: Victor 93 | - family: Towsley 94 | given: Don 95 | blt-type: report 96 | genre: technical report 97 | id: padhye 98 | issued: 1999 99 | number: 99-02 100 | publisher: University of Massachusetts 101 | publisher-place: Amherst, Mass. 102 | title: A stochastic model of TCP Reno congestion avoidance and control 103 | type: report 104 | -------------------------------------------------------------------------------- /citeproc-prange.el: -------------------------------------------------------------------------------- 1 | ;;; citeproc-prange.el --- page-range rendering -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright (C) 2017 András Simonyi 4 | 5 | ;; Author: András Simonyi 6 | 7 | ;; This program is free software; you can redistribute it and/or modify 8 | ;; it under the terms of the GNU General Public License as published by 9 | ;; the Free Software Foundation, either version 3 of the License, or 10 | ;; (at your option) any later version. 11 | 12 | ;; This program is distributed in the hope that it will be useful, 13 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | ;; GNU General Public License for more details. 16 | 17 | ;; You should have received a copy of the GNU General Public License 18 | ;; along with this program. If not, see . 19 | 20 | ;; This file is not part of GNU Emacs. 21 | 22 | ;;; Commentary: 23 | 24 | ;; Functions to render CSL page-ranges. 25 | 26 | ;;; Code: 27 | 28 | (require 'citeproc-s) 29 | 30 | (defun citeproc-prange--end-significant (start end len) 31 | "Return the significant digits of the end in page range START END. 32 | START and END are strings of equal length containing integers. If 33 | the significant part of END is shorter than LEN then add 34 | insignificant digits from END until the string is LEN long or 35 | there are no more digits left." 36 | (let ((first (min (max 1 (1+ (- (length end) len))) 37 | (abs (compare-strings start nil nil end nil nil))))) 38 | (substring end (1- first)))) 39 | 40 | (defun citeproc-prange--end-complete (start end len) 41 | "Complete the closing form of a START END pagerange to LEN." 42 | (citeproc-prange--end-significant start (citeproc-s-fill-copy end start) len)) 43 | 44 | (defun citeproc-prange--end-expanded (_start end end-pref) 45 | "Render the end of range _START END in `expanded' format. 46 | END-PREF is an optional non-numeric prefix preceding END. All 47 | arguments are strings, END has the same length as START." 48 | (concat end-pref end)) 49 | 50 | (defun citeproc-prange--end-minimal (start end _end-pref) 51 | "Render the end of range START END in `minimal' format. 52 | END-PREFIX is an optional non-numeric prefix preceding END. All 53 | arguments are strings, END has the same length as START." 54 | (citeproc-prange--end-significant start end 1)) 55 | 56 | (defun citeproc-prange--end-minimal-two (start end _end-pref) 57 | "Render the end of range START END in `minimal-two' format. 58 | END-PREFIX is an optional non-numeric prefix preceding END. All 59 | arguments are strings, END has the same length as START." 60 | (citeproc-prange--end-significant start end 2)) 61 | 62 | (defun citeproc-prange--end-chicago (start end _end-pref &optional 15th-ed) 63 | "Render the end of range START END in `chicago' format. 64 | END-PREFIX is an optional non-numeric prefix preceding END. All 65 | arguments are strings, END has the same length as START. If 66 | optional 15TH-ED is non-nil then use the special 4digit rule of 67 | the 15th edition." 68 | (let ((len (length start))) 69 | (cond ((or (< len 3) (string= (substring start -2) "00")) 70 | end) 71 | ((string= (substring start -2 -1) "0") 72 | (citeproc-prange--end-significant start end 1)) 73 | ((and 15th-ed (= 4 (length start))) 74 | (let ((min-two (citeproc-prange--end-significant start end 2))) 75 | (if (> (length min-two) 2) end min-two))) 76 | (t (citeproc-prange--end-significant start end 2))))) 77 | 78 | (defconst citeproc-prange-formatters-alist 79 | `((chicago . ,(lambda (start end end-pref) 80 | (citeproc-prange--end-chicago start end end-pref t))) 81 | (chicago-15 . ,(lambda (start end end-pref) 82 | (citeproc-prange--end-chicago start end end-pref t))) 83 | (chicago-16 . citeproc-prange--end-chicago) 84 | (minimal . citeproc-prange--end-minimal) 85 | (minimal-two . citeproc-prange--end-minimal-two) 86 | (expanded . citeproc-prange--end-expanded)) 87 | "Alist mapping page range formats to formatter functions.") 88 | 89 | (defun citeproc-prange-render (p format sep) 90 | "Render page range P in FORMAT with separator SEP." 91 | (with-temp-buffer 92 | (insert p) 93 | (goto-char 0) 94 | (while (search-forward-regexp 95 | "\\([[:digit:]]*[[:alpha:]]\\)?\\([[:digit:]]+\\)\\( ?\\)\\([-–—]+\\)\\( ?\\)\\([[:digit:]]*[[:alpha:]]\\)?\\([[:digit:]]+\\)" 96 | nil t) 97 | (let* ((start-pref (match-string 1)) 98 | (start-num (match-string 2)) 99 | (orig-dash (match-string 4)) 100 | (orig-sep (concat (match-string 3) orig-dash (match-string 5))) 101 | (end-pref (match-string 6)) 102 | (end-num (match-string 7)) 103 | (end (concat end-pref end-num)) 104 | (old-sep-w-end (concat orig-sep end)) 105 | ;; Note: To conform with the official CSL tests we don't replace the separating 106 | ;; dash with SEP if collapse cannot be applied because of incompatible prefixes 107 | ;; but we still remove spaces surrounding the dash. It would make far more 108 | ;; sense to replace the dash as well. 109 | (new-sep-w-end (cond ((not (string= start-pref end-pref)) 110 | (concat orig-dash end)) 111 | ;; Deal with degenerate single page "ranges" 112 | ((string= start-num end-num) 113 | "") 114 | ((or (not format) (> (length end-num) (length start-num))) 115 | (concat sep end)) 116 | (t (concat 117 | sep 118 | (funcall (alist-get format 119 | citeproc-prange-formatters-alist) 120 | start-num 121 | (citeproc-s-fill-copy end-num start-num) 122 | end-pref)))))) 123 | (unless (string-equal new-sep-w-end old-sep-w-end) 124 | (delete-char (- (length old-sep-w-end))) 125 | (insert new-sep-w-end)))) 126 | (buffer-string))) 127 | 128 | (provide 'citeproc-prange) 129 | 130 | ;;; citeproc-prange.el ends here 131 | -------------------------------------------------------------------------------- /citeproc-lib.el: -------------------------------------------------------------------------------- 1 | ;;; citeproc-lib.el --- misc functions and variables for citeproc-el -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright (C) 2017-2021 András Simonyi 4 | 5 | ;; Author: András Simonyi 6 | 7 | ;; This program is free software; you can redistribute it and/or modify 8 | ;; it under the terms of the GNU General Public License as published by 9 | ;; the Free Software Foundation, either version 3 of the License, or 10 | ;; (at your option) any later version. 11 | 12 | ;; This program is distributed in the hope that it will be useful, 13 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | ;; GNU General Public License for more details. 16 | 17 | ;; You should have received a copy of the GNU General Public License 18 | ;; along with this program. If not, see . 19 | 20 | ;; This file is not part of GNU Emacs. 21 | 22 | ;;; Commentary: 23 | 24 | ;; General utility functions used in citeproc-el. 25 | 26 | ;;; Code: 27 | 28 | (require 'dash) 29 | (require 's) 30 | 31 | (defconst citeproc--number-vars 32 | '(chapter-number citation-number collection-number edition first-reference-note-number 33 | issue number number-of-pages number-of-volumes page page-first 34 | part-number printing-number section supplement-number version volume) 35 | "CSL number variables." 36 | ;; Note: `locator', which is also on the official list, is omitted because 37 | ;; it's treated specially in the code. 38 | ) 39 | 40 | (defconst citeproc--date-vars 41 | '(accessed available-date event-date issued original-date submitted locator-date) 42 | "CSL date variables.") 43 | 44 | (defconst citeproc--name-vars 45 | '(author chair collection-editor compiler composer container-author contributor 46 | curator director editor editorial-director editor-translator executive-producer 47 | guest host illustrator interviewer narrator organizer original-author 48 | performer producer recipient reviewed-author script-writer series-creator 49 | translator) 50 | "CSL name variables.") 51 | 52 | (defconst citeproc--linked-vars 53 | '(DOI PMCID PMID URL) 54 | "Variables whose rendered content should be linked. 55 | The ordering is according to priority ") 56 | 57 | (defconst citeproc--link-prefix-alist 58 | '((DOI . "https://doi.org/") 59 | (PMID . "https://www.ncbi.nlm.nih.gov/pubmed/") 60 | (PMCID . "https://www.ncbi.nlm.nih.gov/pmc/articles/")) 61 | "Alist mapping variable names to uri prefixes.") 62 | 63 | (defun citeproc-lib-parse-xml-file (file) 64 | "Return the parsed xml representation of FILE." 65 | (with-temp-buffer 66 | (insert-file-contents file) 67 | (libxml-parse-xml-region (point-min) (point-max)))) 68 | 69 | (defun citeproc-lib-remove-xml-comments (tree) 70 | "Remove comments from xml TREE." 71 | (let ((head (car tree)) 72 | (attrs (cadr tree)) 73 | (body (cddr tree)) 74 | result) 75 | (while body 76 | (pcase (car body) 77 | ((pred atom) (push (pop body) result)) 78 | (`(comment . ,_) (pop body)) 79 | (_ (push (citeproc-lib-remove-xml-comments (pop body)) result)))) 80 | (let ((full-result (cons head (cons attrs (nreverse result))))) 81 | ;; Handle the problem of the top element added by the libxml parser when 82 | ;; there is a comment after the xml declaration. 83 | (if (eq (car full-result) 'top) 84 | (caddr full-result) 85 | full-result)))) 86 | 87 | (defun citeproc-lib-parse-html-frag (s) 88 | "Return the parsed representation of html in string S." 89 | (with-temp-buffer 90 | (insert s) 91 | (libxml-parse-html-region (point-min) (point-max)))) 92 | 93 | (defun citeproc-lib-intern (s) 94 | "Intern S if it is a string, return nil if it is nil." 95 | (cond ((not s) nil) 96 | ((stringp s) (intern s)) 97 | (t (error "Function citeproc-lib-intern was called with an argument that is neither string nor nil")))) 98 | 99 | (defun citeproc-lib-named-parts-to-alist (e) 100 | "Collect the attrs of parsed xml element E's enclosed elements. 101 | The attributes are collected into an alist consisting 102 | of (PARTNAME . ATTRS) pairs, where PARTNAME is the value of the 103 | enclosed element's `name' attr" 104 | (--map (cons (intern (alist-get 'name it)) 105 | (assq-delete-all 'name it)) 106 | (mapcar #'cadr (-remove #'stringp (cddr e))))) 107 | 108 | (defun citeproc-lib-lex-compare (l1 l2 cmp-fun sort-orders) 109 | "Whether list L1 lexicographically precedes list L2. 110 | CMP-FUN is a three-valued (1, 0, -1) comparator function, 111 | SORT-ORDERS is a list of sort orders (see the bib- and 112 | cite-sort-orders slots of `citeproc-style' for details). Return t 113 | iff L1 is strictly ordered before L2, nil otherwise." 114 | (unless sort-orders 115 | (setq sort-orders (make-list (length l1) t))) 116 | (let (result) 117 | (while (and l1 (not result)) 118 | (let ((comp 119 | (funcall cmp-fun (pop l1) (pop l2) (not (pop sort-orders))))) 120 | (unless (= comp 0) 121 | (setq result comp)))) 122 | (equal result 1))) 123 | 124 | (defun citeproc-lib-splice-into (list tag) 125 | "Splice elements with car TAG into LIST." 126 | (let (result) 127 | (dolist (elt list) 128 | (if (and (consp elt) (eq tag (car elt))) 129 | (dolist (e (cdr elt)) 130 | (push e result)) 131 | (push elt result))) 132 | (nreverse result))) 133 | 134 | (defun citeproc-lib-add-splice-tag (list tag) 135 | "Add TAG as car if LIST is not a singleton. 136 | Return the first element if LIST is singleton." 137 | (if (cdr list) (cons tag list) (car list))) 138 | 139 | (defun citeproc-lib-numeric-p (val) 140 | "Return whether VAL is numeric content. 141 | VAL has numeric content if it is a number or a string containing 142 | numeric content." 143 | (or (numberp val) 144 | (and (stringp val) 145 | (s-matches-p "\\`[[:alpha:]]?[[:digit:]]+[[:alpha:]]*\\(\\( *\\([,&-]\\|--\\) *\\)?[[:alpha:]]?[[:digit:]]+[[:alpha:]]*\\)?\\'" 146 | val)))) 147 | 148 | (provide 'citeproc-lib) 149 | 150 | ;;; citeproc-lib.el ends here 151 | -------------------------------------------------------------------------------- /test/biblatex_csl/patent.txt: -------------------------------------------------------------------------------- 1 | --- 2 | @patent{almendro, 3 | Annotation = {This is a patent entry with a location field. The number is given in the number field. Note the format of the location field in the database file. Compare laufenberg, sorace, and kowalik}, 4 | Author = {Almendro, José L. and Martín, Jacinto and Sánchez, Alberto and Nozal, Fernando}, 5 | Date = 1998, 6 | Location = {France; United Kingdom; Germany}, 7 | Number = {EU-29702195U}, 8 | Title = {Elektromagnetisches Signalhorn}, 9 | Langid = {german}} 10 | 11 | @patent{kowalik, 12 | Annotation = {This is a patent entry for a French patent request with a full date. The number is given in the number field. Note the format of the type and date fields in the database file. Compare almendro, laufenberg, and sorace}, 13 | Author = {Kowalik, F. and Isard, M.}, 14 | Date = {1995-01-11}, 15 | Indextitle = {Estimateur d'un défaut de fonctionnement}, 16 | Number = 9500261, 17 | Title = {Estimateur d'un défaut de fonctionnement d'un modulateur en quadrature et étage de modulation l'utilisant}, 18 | Type = {patreqfr}, 19 | Langid = {french}} 20 | 21 | @patent{laufenberg, 22 | Annotation = {This is a patent entry with a holder field. Note the format of the type and location fields in the database file. Compare almendro, sorace, and kowalik}, 23 | Author = {Laufenberg, Xaver and Eynius, Dominique and Suelzle, Helmut and Usbeck, Stephan and Spaeth, Matthias and Neuser-Hoffmann, Miriam and Myrzik, Christian and Schmid, Manfred and Nietfeld, Franz and Thiel, Alexander and Braun, Harald and Ebner, Norbert}, 24 | Date = {2006-09-13}, 25 | File = {http://v3.espacenet.com/textdoc?IDX=EP1700367}, 26 | Holder = {{Robert Bosch GmbH} and {Daimler Chrysler AG} and {Bayerische Motoren Werke AG}}, 27 | Number = 1700367, 28 | Title = {Elektrische Einrichtung und Betriebsverfahren}, 29 | Type = {patenteu}, 30 | Abstract = {The invention relates to an electric device comprising a 31 | generator, in particular for use in the vehicle electric 32 | system of a motor vehicle and a controller for controlling the 33 | generator voltage. The device is equipped with a control zone, 34 | in which the voltage is controlled and zones, in which the 35 | torque is controlled. The invention also relates to methods 36 | for operating a device of this type.}, 37 | Langid = {german}} 38 | 39 | @patent{sorace, 40 | Annotation = {This is a patent entry with a holder field. Note the format of the type and date fields in the database file. Compare almendro, laufenberg, and kowalik}, 41 | Author = {Sorace, Ronald E. and Reinhardt, Victor S. and Vaughn, Steven A.}, 42 | Date = {1997-09-16}, 43 | Date-Modified = {2013-10-16 13:44:15 +0000}, 44 | Holder = {{Hughes Aircraft Company}}, 45 | Hyphenation = {american}, 46 | Number = 5668842, 47 | Title = {High-Speed Digital-to-{RF} Converter}, 48 | Type = {patentus}} 49 | 50 | --- 51 | - annote: This is a patent entry with a location field. The number is 52 | given in the number field. Note the format of the location field in 53 | the database file. Compare laufenberg, sorace, and kowalik 54 | author: 55 | - family: Almendro 56 | given: José L. 57 | - family: Martín 58 | given: Jacinto 59 | - family: Sánchez 60 | given: Alberto 61 | - family: Nozal 62 | given: Fernando 63 | blt-type: patent 64 | id: almendro 65 | issued: 1998 66 | language: de-DE 67 | jurisdiction: France; United Kingdom; Germany 68 | number: EU-29702195U 69 | title: Elektromagnetisches Signalhorn 70 | type: patent 71 | - annote: This is a patent entry for a French patent request with a full 72 | date. The number is given in the number field. Note the format of 73 | the type and date fields in the database file. Compare almendro, 74 | laufenberg, and sorace 75 | author: 76 | - family: Kowalik 77 | given: F. 78 | - family: Isard 79 | given: M. 80 | blt-type: patent 81 | genre: French patent request 82 | id: kowalik 83 | issued: 1995-01-11 84 | language: fr-FR 85 | number: 9500261 86 | title: Estimateur d'un défaut de fonctionnement d'un modulateur en 87 | quadrature et étage de modulation l'utilisant 88 | type: patent 89 | - abstract: The invention relates to an electric device comprising a 90 | generator, in particular for use in the vehicle electric system of a 91 | motor vehicle and a controller for controlling the generator 92 | voltage. The device is equipped with a control zone, in which the 93 | voltage is controlled and zones, in which the torque is controlled. 94 | The invention also relates to methods for operating a device of this 95 | type. 96 | annote: This is a patent entry with a holder field. Note the format of 97 | the type and location fields in the database file. Compare almendro, 98 | sorace, and kowalik 99 | author: 100 | - family: Laufenberg 101 | given: Xaver 102 | - family: Eynius 103 | given: Dominique 104 | - family: Suelzle 105 | given: Helmut 106 | - family: Usbeck 107 | given: Stephan 108 | - family: Spaeth 109 | given: Matthias 110 | - family: Neuser-Hoffmann 111 | given: Miriam 112 | - family: Myrzik 113 | given: Christian 114 | - family: Schmid 115 | given: Manfred 116 | - family: Nietfeld 117 | given: Franz 118 | - family: Thiel 119 | given: Alexander 120 | - family: Braun 121 | given: Harald 122 | - family: Ebner 123 | given: Norbert 124 | blt-type: patent 125 | genre: European patent 126 | id: laufenberg 127 | issued: 2006-09-13 128 | language: de-DE 129 | number: 1700367 130 | title: Elektrische Einrichtung und Betriebsverfahren 131 | type: patent 132 | - annote: This is a patent entry with a holder field. Note the format of 133 | the type and date fields in the database file. Compare almendro, 134 | laufenberg, and kowalik 135 | author: 136 | - family: Sorace 137 | given: Ronald E. 138 | - family: Reinhardt 139 | given: Victor S. 140 | - family: Vaughn 141 | given: Steven A. 142 | blt-type: patent 143 | genre: U.S. patent 144 | id: sorace 145 | issued: 1997-09-16 146 | number: 5668842 147 | title: High-speed digital-to-RF converter 148 | type: patent 149 | 150 | -------------------------------------------------------------------------------- /citeproc-number.el: -------------------------------------------------------------------------------- 1 | ;;; citeproc-number.el --- render CSL number elements -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright "(C) 2017 András Simonyi 4 | 5 | ;; Author: András Simonyi 6 | 7 | ;; This program is free software; you can redistribute it and/or modify 8 | ;; it under the terms of the GNU General Public License as published by 9 | ;; the Free Software Foundation, either version 3 of the License, or 10 | ;; (at your option) any later version. 11 | 12 | ;; This program is distributed in the hope that it will be useful, 13 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | ;; GNU General Public License for more details. 16 | 17 | ;; You should have received a copy of the GNU General Public License 18 | ;; along with this program. If not, see . 19 | 20 | ;; This file is not part of GNU Emacs. 21 | 22 | ;;; Commentary: 23 | 24 | ;; Functions to render CSL number elements. 25 | 26 | ;;; Code: 27 | 28 | (require 'subr-x) 29 | (require 'rst) 30 | (require 's) 31 | 32 | (require 'citeproc-context) 33 | (require 'citeproc-lib) 34 | (require 'citeproc-s) 35 | (require 'citeproc-rt) 36 | 37 | (defun citeproc-number-extract (val) 38 | "Return the parse of string VAL holding numeric content." 39 | (cdr (s-match 40 | "\\`\\([[:alpha:]]?[[:digit:]]+[[:alpha:]]*\\)\\(?:\\(?: *\\([,&-–—―]\\|--\\) *\\)\\([[:alpha:]]?[[:digit:]]+[[:alpha:]]*\\)\\)?\\'" 41 | val))) 42 | 43 | (defun citeproc--number (attrs context &rest _body) 44 | "Render a cs:number element with the given ATTRS in CONTEXT." 45 | (-let* (((&alist 'variable var 46 | 'form form) 47 | attrs) 48 | (variable (intern var)) 49 | (value (citeproc-var-value variable context)) 50 | (form (citeproc-lib-intern form))) 51 | (if (not value) 52 | (cons nil 'empty-var) 53 | (let ((result-attrs 54 | (cons `(rendered-var . ,variable) attrs)) 55 | (result-cont 56 | (citeproc-number-var-value value variable form context))) 57 | (cons (citeproc-rt-format-single result-attrs result-cont context) 58 | 'present-var))))) 59 | 60 | (defconst citeproc--format-numsep-alist 61 | '(("&" . " & ") 62 | ("," . ", ") 63 | ("-" . "-") 64 | ("--" . "-") 65 | ("—" . "-") 66 | ("―" . "-")) 67 | "Alist specifying the proper formatting of number-pair separators.") 68 | 69 | (defun citeproc-number-var-value (value variable form context) 70 | "Return the numeric VALUE of VARIABLE formatted in FORM. 71 | VARIABLE is a symbol." 72 | (cond ((not value) nil) 73 | ((numberp value) (number-to-string value)) 74 | (t (--if-let (citeproc-number-extract value) 75 | (let ((formatted-first 76 | (citeproc-number--format (car it) form variable context))) 77 | (if (> (length it) 1) 78 | (concat 79 | formatted-first 80 | (assoc-default (cadr it) citeproc--format-numsep-alist) 81 | (citeproc-number--format (cl-caddr it) form variable context)) 82 | formatted-first)) 83 | value)))) 84 | 85 | (defun citeproc-number--format (s form term context) 86 | "Render the number in string S for TERM in format FORM." 87 | (if (s-matches-p "[[:alpha:]]" s) s 88 | (pcase form 89 | ('roman (downcase (rst-arabic-to-roman (string-to-number s)))) 90 | ('ordinal (citeproc-number--format-as-ordinal s term context)) 91 | ('long-ordinal (citeproc-number--format-as-long-ordinal s term context)) 92 | (_ s)))) 93 | 94 | (defun citeproc-number--format-as-ordinal (s term context) 95 | "Format numeric string S as ordinal agreeing with TERM." 96 | (let* ((terms (citeproc-context-terms context)) 97 | (padded (if (= 1 (length s)) 98 | (concat "0" s) 99 | s)) 100 | (gender (citeproc-term-get-gender term context)) 101 | (matches 102 | (--filter (and (string= (s-left 8 (citeproc-term-name it)) "ordinal-") 103 | (citeproc-number--ordinal-matches-p padded gender it)) 104 | terms)) 105 | (suffix 106 | (citeproc-term-text 107 | (if (not matches) 108 | (-when-let (ordinal-matches 109 | (--filter (string= (citeproc-term-name it) "ordinal") 110 | terms)) 111 | (-if-let (match (--first (eq (citeproc-term-gender-form it) gender) 112 | ordinal-matches)) 113 | match 114 | (car ordinal-matches))) 115 | (let ((first-term (car matches))) 116 | (-if-let (second-term (cadr matches)) 117 | (if (= (elt (citeproc-term-name first-term) 8) ?0) 118 | second-term 119 | first-term) 120 | first-term)))))) 121 | (concat s suffix))) 122 | 123 | (defconst citeproc-number--ordinal-match-alist 124 | '((last-two-digits . 2) 125 | (last-digit . 1) 126 | (whole-number . nil)) 127 | "Alist mapping ordinal match attributes to the required match lengths.") 128 | 129 | (defun citeproc-number--ordinal-matches-p (s gender ord-term) 130 | "Whether S term with GENDER matches ordinal-term ORD-TERM." 131 | (and (eq gender (citeproc-term-gender-form ord-term)) 132 | (let ((match (citeproc-term-match ord-term)) 133 | (term-num (s-right 2 (citeproc-term-name ord-term)))) 134 | (unless match 135 | (setq match 136 | (if (= (elt (citeproc-term-name ord-term) 8) ?0) 137 | 'last-digit 138 | 'last-two-digits))) 139 | (let ((l (assoc-default match citeproc-number--ordinal-match-alist))) 140 | (string= (citeproc-s-tail s l) 141 | (citeproc-s-tail term-num l)))))) 142 | 143 | (defun citeproc-number--format-as-long-ordinal (s term context) 144 | "Format numeric string S as a long ordinal agreeing with TERM." 145 | (let ((num-val (string-to-number s))) 146 | (if (> num-val 10) 147 | (citeproc-number--format-as-ordinal s term context) 148 | (when (= 1 (length s)) (setq s (concat "0" s))) 149 | (let* ((name (concat "long-ordinal-" s)) 150 | (gender (citeproc-term-get-gender term context)) 151 | (match (--first (and (string= (citeproc-term-name it) name) 152 | (eq (citeproc-term-gender-form it) gender)) 153 | (citeproc-context-terms context)))) 154 | (if match 155 | (citeproc-term-text match) 156 | (citeproc-term-get-text name context)))))) 157 | 158 | (provide 'citeproc-number) 159 | 160 | ;;; citeproc-number ends here 161 | -------------------------------------------------------------------------------- /citeproc-generic-elements.el: -------------------------------------------------------------------------------- 1 | ;;; citeproc-generic-elements.el --- render generic CSL elements -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright (C) 2017-2021 András Simonyi 4 | 5 | ;; Author: András Simonyi 6 | 7 | ;; This program is free software; you can redistribute it and/or modify 8 | ;; it under the terms of the GNU General Public License as published by 9 | ;; the Free Software Foundation, either version 3 of the License, or 10 | ;; (at your option) any later version. 11 | 12 | ;; This program is distributed in the hope that it will be useful, 13 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | ;; GNU General Public License for more details. 16 | 17 | ;; You should have received a copy of the GNU General Public License 18 | ;; along with this program. If not, see . 19 | 20 | ;; This file is not part of GNU Emacs. 21 | 22 | ;;; Commentary: 23 | 24 | ;; Functions corresponding to the generic CSL rendering elements cs:layout, 25 | ;; cs:group and cs:text. With the exception of `citeproc--layout' they return a 26 | ;; (CONTENT . CONTENT-TYPE) pair, where CONTENT is the rendered rich-text output 27 | ;; and CONTENT-TYPE is one of the symbols `text-only', `empty-vars' and 28 | ;; `present-var.' In contrast, `citeproc--layout' returns only the rendered 29 | ;; rich-text content. 30 | 31 | ;;; Code: 32 | 33 | (require 'dash) 34 | (require 'let-alist) 35 | (require 's) 36 | 37 | (require 'citeproc-rt) 38 | (require 'citeproc-context) 39 | (require 'citeproc-macro) 40 | 41 | (defun citeproc--layout (attrs context &rest body) 42 | "Render the content of a layout element with ATTRS and BODY." 43 | (let* ((attrs (if (eq (citeproc-context-mode context) 'bib) attrs 44 | nil)) ; No attrs if mode is cite -- they are used for citations 45 | (spliced-body (citeproc-lib-splice-into body 'splice)) 46 | (suffix (alist-get 'suffix attrs)) 47 | (attrs-wo-suffix (--remove (eq (car it) 'suffix) attrs)) 48 | (rendered-body (--map (car it) spliced-body))) 49 | ;; Handle second-field align 50 | (when (and (alist-get 'second-field-align (citeproc-context-opts context)) 51 | (> (length rendered-body) 1)) 52 | (setq rendered-body `((((display . "left-margin")) ,(car rendered-body)) 53 | (((display . "right-inline")) ,@(cdr rendered-body))))) 54 | (let* ((affix-rendered (citeproc-rt-render-affixes 55 | (citeproc-rt-dedup (citeproc-rt-join-formatted attrs-wo-suffix rendered-body 56 | context)))) 57 | (last-elt (and (listp affix-rendered) (-last-item affix-rendered))) 58 | (last-display (and (consp last-elt) (car last-elt) 59 | (--any-p (eq (car it) 'display) (car last-elt))))) 60 | (when suffix 61 | (if last-display 62 | ;; If the last element has a display attribute then we have to append the 63 | ;; suffix string to this last element 64 | (setf (nth (1- (length affix-rendered)) affix-rendered) 65 | (-snoc (-last-item affix-rendered) suffix)) 66 | ;; Else we simply append it to the already rendered content 67 | (setq affix-rendered (if (listp affix-rendered) 68 | (-snoc affix-rendered suffix) 69 | (concat affix-rendered suffix))))) 70 | affix-rendered))) 71 | 72 | (defun citeproc--group (attrs context &rest body) 73 | "Render the content of a group element with ATTRS and BODY." 74 | (-let* ((spliced-body (citeproc-lib-splice-into body 'splice)) 75 | (types (--map (cdr it) spliced-body)) 76 | (type (cond ((--all? (eq it 'text-only) types) 77 | 'text-only) 78 | ((--any? (eq it 'present-var) types) 79 | 'present-var) 80 | (t 'empty-vars)))) 81 | (cons (if (or (eq type 'text-only) 82 | (eq type 'present-var)) 83 | (citeproc-rt-join-formatted attrs (--map (car it) spliced-body) context) 84 | nil) 85 | type))) 86 | 87 | (defconst citeproc-generic-elements--url-prefix-re "https?://\\S *\\'" 88 | "Regex matching an URL prefix at the end of a string.") 89 | 90 | (defun citeproc--text (attrs context &rest _body) 91 | "Render the content of a text element with ATTRS and BODY." 92 | (let-alist attrs 93 | (let ((content nil) 94 | (type 'text-only) 95 | (no-external-links (citeproc-context-no-external-links context))) 96 | (cond (.value (setq content .value)) 97 | (.variable 98 | (let ((val (citeproc-var-value (intern .variable) context (citeproc-lib-intern 99 | .form)))) 100 | (setq content val) 101 | (cond 102 | (val (let ((var (intern .variable))) 103 | (setq type 'present-var) 104 | (push `(rendered-var . ,var) attrs) 105 | (when (and (not no-external-links) 106 | (memq var citeproc--linked-vars)) 107 | (let ((target 108 | (concat 109 | (alist-get var citeproc--link-prefix-alist 110 | "") 111 | content))) 112 | (-when-let (match-pos 113 | (and .prefix (s-matched-positions-all 114 | citeproc-generic-elements--url-prefix-re 115 | .prefix))) 116 | ;; If the prefix ends with an URL then it is moved 117 | ;; from the prefix to the rendered variable 118 | ;; content. 119 | (let ((start (caar match-pos))) 120 | (setq content (concat (substring .prefix start) content)) 121 | (push (cons 'prefix (substring .prefix 0 start)) 122 | attrs))) 123 | (push (cons 'href target) attrs))))) 124 | ;; Don't report empty var for year-suffix, see issue #70. 125 | ((not (string= .variable "year-suffix")) (setq type 'empty-vars))))) 126 | (.term (setq .form (if .form (intern .form) 'long) 127 | .plural (if (or (not .plural) 128 | (string= .plural "false")) 129 | 'single 'multiple) 130 | content (let ((cont (citeproc-term-inflected-text 131 | .term .form .plural context))) 132 | ;; Annotate the 'no date' term as if it'd be 133 | ;; the value of the 'issue' variable to 134 | ;; handle implicit year suffix addition and 135 | ;; suppression issues. 136 | (if (string= .term "no date") 137 | (progn 138 | (setq type 'present-var) 139 | `(((rendered-var . issued)) ,cont)) 140 | cont)))) 141 | (.macro (let ((macro-val (citeproc-macro-output .macro context))) 142 | (setq content (car macro-val)) 143 | (setq type (cdr macro-val))))) 144 | ;; We stop if only the title had to be rendered. 145 | (let ((result (cons (citeproc-rt-format-single attrs content context) type))) 146 | (citeproc-context-maybe-stop-rendering 147 | 'title context result (or (and .variable (intern .variable)) t)))))) 148 | 149 | (provide 'citeproc-generic-elements) 150 | 151 | ;;; citeproc-generic-elements.el ends here 152 | -------------------------------------------------------------------------------- /citeproc-itemgetters.el: -------------------------------------------------------------------------------- 1 | ;; citeproc-itemgetters.el --- functions for constructing itemgetters -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright (C) 2017-2021 András Simonyi 4 | 5 | ;; Author: András Simonyi 6 | 7 | ;; This program is free software; you can redistribute it and/or modify 8 | ;; it under the terms of the GNU General Public License as published by 9 | ;; the Free Software Foundation, either version 3 of the License, or 10 | ;; (at your option) any later version. 11 | 12 | ;; This program is distributed in the hope that it will be useful, 13 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | ;; GNU General Public License for more details. 16 | 17 | ;; You should have received a copy of the GNU General Public License 18 | ;; along with this program. If not, see . 19 | 20 | ;; This file is not part of GNU Emacs. 21 | 22 | ;;; Commentary: 23 | 24 | ;; Functions for constructing various types of bibliographic itemgetter 25 | ;; functions. The returned itemgetter functions can, in turn, be used to create 26 | ;; `citeproc-style' and `citeproc-proc' structures. 27 | 28 | ;;; Code: 29 | 30 | (require 'dash) 31 | (require 'org) 32 | ;; Handle the fact that org-bibtex has been renamed to ol-bibtex -- for the time 33 | ;; being we support both feature names. 34 | (or (require 'ol-bibtex nil t) 35 | (require 'org-bibtex)) 36 | (require 'json) 37 | (require 'bibtex) 38 | (require 'parsebib) 39 | 40 | (require 'citeproc-bibtex) 41 | (require 'citeproc-biblatex) 42 | 43 | (defun citeproc-itemgetters--parsebib-buffer (entries strings) 44 | "Parse a BibTeX/biblatex buffer with Parsebib." 45 | ;; Note: this is needed to support different Parsebib versions in use. 46 | (cond ((fboundp 'parsebib-parse-buffer) 47 | (parsebib-parse-buffer entries strings t t)) 48 | ((fboundp 'parsebib-parse-bib-buffer) 49 | (parsebib-parse-bib-buffer :entries entries :strings strings 50 | :expand-strings t :inheritance t)) 51 | (t (error "No Parsebib buffer parsing function is available")))) 52 | 53 | (defun citeproc-hash-itemgetter-from-csl-json (file) 54 | "Return a hash-based getter for csl json bibliography FILE." 55 | (let* ((json-array-type 'list) 56 | (json-key-type 'symbol) 57 | (item-list (json-read-file file)) 58 | (hash (make-hash-table :test 'equal))) 59 | (--each item-list 60 | (puthash (alist-get 'id it) it hash)) 61 | (lambda (itemids) (--map (cons it (gethash it hash)) 62 | itemids)))) 63 | 64 | (defun citeproc-itemgetter-from-csl-json (file) 65 | "Return an item-getter for csl json bibliography FILE." 66 | (lambda (itemids) 67 | (let* ((json-array-type 'list) 68 | (json-key-type 'symbol) 69 | (item-list (json-read-file file)) 70 | result) 71 | (dolist (item item-list result) 72 | (let ((id (alist-get 'id item))) 73 | (when (member id itemids) 74 | (push (cons id item) result))))))) 75 | 76 | (defun citeproc-itemgetter-from-bibtex (file-or-files) 77 | "Return a getter for BibTeX bibliography FILE-OR-FILES." 78 | (if (listp file-or-files) 79 | (lambda (itemids) 80 | (let (result 81 | (remaining-ids (cl-copy-list itemids)) 82 | (remaining-files file-or-files)) 83 | (while (and remaining-ids remaining-files) 84 | (let ((file (pop remaining-files))) 85 | (with-temp-buffer 86 | (insert-file-contents file) 87 | (goto-char (point-min)) 88 | (bibtex-set-dialect 'BibTeX t) 89 | (bibtex-map-entries 90 | (lambda (key _beg _end) 91 | (when (member key itemids) 92 | (push (cons key (citeproc-bt-entry-to-csl (bibtex-parse-entry))) 93 | result) 94 | (setq remaining-ids (delete key remaining-ids)))))))) 95 | result)) 96 | (lambda (itemids) 97 | (let (result) 98 | (with-temp-buffer 99 | (insert-file-contents file-or-files) 100 | (goto-char (point-min)) 101 | (bibtex-set-dialect 'BibTeX t) 102 | (bibtex-map-entries 103 | (lambda (key _beg _end) 104 | (when (member key itemids) 105 | (push (cons key (citeproc-bt-entry-to-csl (bibtex-parse-entry))) 106 | result))))) 107 | result)))) 108 | 109 | (defun citeproc-itemgetter-from-org-bibtex (file-or-files) 110 | "Return a getter for org-bibtex bibliography FILE-OR-FILES." 111 | (let ((files (if (listp file-or-files) 112 | file-or-files 113 | (list file-or-files)))) 114 | (lambda (itemids) 115 | (let (result) 116 | (org-map-entries 117 | (lambda () 118 | (-when-let (key-w-entry (citeproc-bt-from-org-headline itemids)) 119 | (push (cons (car key-w-entry) 120 | (citeproc-bt-entry-to-csl (cdr key-w-entry))) 121 | result))) 122 | t files) 123 | result)))) 124 | 125 | (defun citeproc-hash-itemgetter-from-any (file-or-files &optional no-sentcase-wo-langid) 126 | "Return a getter for FILE-OR-FILES in any supported format. 127 | The format is determined on the basis of file extensions. 128 | Supported formats: 129 | - CSL-JSON (.json extension) the recommended native format; 130 | - BibTeX/biblatex (.bib or .bibtex extension), 131 | - org-bibtex (.org extension). 132 | If NO-SENTCASE-WO-LANGID is non-nil then title fields in items 133 | without a `langid' field are not converted to sentence-case." 134 | (let ((files (if (listp file-or-files) 135 | file-or-files 136 | (list file-or-files))) 137 | (cache (make-hash-table :test #'equal)) 138 | (bt-entries (make-hash-table :test #'equal)) 139 | (bt-strings (make-hash-table :test #'equal))) 140 | (dolist (file files) 141 | (pcase (file-name-extension file) 142 | ("json" 143 | (let ((json-array-type 'list) 144 | (json-key-type 'symbol)) 145 | (dolist (item (json-read-file file)) 146 | (puthash (cdr (assq 'id item)) item cache)))) 147 | ((and (or "bib" "bibtex") ext) 148 | (with-temp-buffer 149 | (insert-file-contents file) 150 | (bibtex-set-dialect (if (string= ext "bib") 'biblatex 'BibTeX) t) 151 | (citeproc-itemgetters--parsebib-buffer bt-entries bt-strings))) 152 | ("org" 153 | (org-map-entries 154 | (lambda () 155 | (-when-let (key-w-entry (citeproc-bt-from-org-headline)) 156 | (condition-case err 157 | (puthash (car key-w-entry) (citeproc-blt-entry-to-csl 158 | (cdr key-w-entry)) 159 | cache) 160 | (error 161 | (user-error 162 | "Couldn't parse the bib(la)tex entry with key '%s', the error was: %s" 163 | (car key-w-entry) err))))) 164 | t (list file))) 165 | (ext 166 | (user-error "Unknown bibliography extension: %S" ext)))) 167 | (maphash 168 | (lambda (key entry) 169 | (condition-case err 170 | (puthash key (citeproc-blt-entry-to-csl entry nil no-sentcase-wo-langid) 171 | cache) 172 | (error 173 | (user-error 174 | "Couldn't parse the bib(la)tex entry with key '%s', the error was: %s" 175 | key err)))) 176 | bt-entries) 177 | (lambda (x) 178 | (pcase x 179 | ('itemids 180 | (hash-table-keys cache)) 181 | ((pred listp) (mapcar (lambda (id) 182 | (cons id (gethash id cache))) 183 | x)) 184 | (_ (error "Unsupported citeproc itemgetter retrieval method")))))) 185 | 186 | (provide 'citeproc-itemgetters) 187 | 188 | ;;; citeproc-itemgetters.el ends here 189 | -------------------------------------------------------------------------------- /citeproc-sort.el: -------------------------------------------------------------------------------- 1 | ;;; citeproc-sort.el --- cite and bibliography sorting -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright (C) 2017 András Simonyi 4 | 5 | ;; Author: András Simonyi 6 | 7 | ;; This program is free software; you can redistribute it and/or modify 8 | ;; it under the terms of the GNU General Public License as published by 9 | ;; the Free Software Foundation, either version 3 of the License, or 10 | ;; (at your option) any later version. 11 | 12 | ;; This program is distributed in the hope that it will be useful, 13 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | ;; GNU General Public License for more details. 16 | 17 | ;; You should have received a copy of the GNU General Public License 18 | ;; along with this program. If not, see . 19 | 20 | ;; This file is not part of GNU Emacs. 21 | 22 | ;;; Commentary: 23 | 24 | ;; Functions to sort cites and bibliography items. 25 | 26 | ;;; Code: 27 | 28 | (require 'subr-x) 29 | (require 'cl-lib) 30 | (require 'dash) 31 | (require 's) 32 | 33 | (require 'citeproc-lib) 34 | (require 'citeproc-s) 35 | (require 'citeproc-rt) 36 | (require 'citeproc-macro) 37 | (require 'citeproc-proc) 38 | (require 'citeproc-name) 39 | (require 'citeproc-number) 40 | 41 | (defun citeproc--sort (_attrs _context &rest body) 42 | "Placeholder function corresponding to the cs:sort element of CSL." 43 | body) 44 | 45 | (defun citeproc-sort--name-var-key (var context) 46 | "Return the sort-key for name-var VAR using CONTEXT. 47 | VAR is a CSL name-var name as a symbol. The returned value is a 48 | string containing a semicolon-separated list of all full names in 49 | sort order." 50 | (citeproc-rt-to-plain 51 | (citeproc-rt-render-affixes 52 | (citeproc-name--render-var var '((form . "long") (name-as-sort-order . "all") 53 | (et-al-min . nil) (et-al-use-first . "0") 54 | (delimiter . "; ")) 55 | nil nil nil nil nil context)))) 56 | 57 | (defun citeproc-sort--date-as-key (d _context) 58 | "Render D citeproc-date struct as a sort key." 59 | (if d (let ((year (citeproc-date-year d)) 60 | (month (or (citeproc-date-month d) 0)) 61 | (day (or (citeproc-date-day d) 0))) 62 | ;; We add 5000 as an offset to deal with sorting BC years properly 63 | (concat (number-to-string (+ 5000 year)) 64 | (citeproc-s-fill-left-to-len (number-to-string month) 2 ?0) 65 | (citeproc-s-fill-left-to-len (number-to-string day) 2 ?0))) 66 | "")) 67 | 68 | (defun citeproc-sort--date-var-key (var context) 69 | "Return the sort-key for name-var VAR using CONTEXT. 70 | VAR is a symbol." 71 | (-let* (((d1 d2) (citeproc-var-value var context)) 72 | (rendered-first (citeproc-sort--date-as-key d1 context))) 73 | (if d2 74 | (concat rendered-first "–" (citeproc-sort--date-as-key d2 context)) 75 | rendered-first))) 76 | 77 | (defun citeproc--key (attrs context &rest _body) 78 | "Return a sort key corresponding to ATTRS and CONTEXT." 79 | (-let (((&alist 'macro macro 80 | 'variable var) 81 | attrs) 82 | (global-attrs (--filter (memq (car it) 83 | '(names-min names-use-first names-use-last)) 84 | attrs))) 85 | (if var (let ((var-sym (intern var))) 86 | (cond 87 | ((memq var-sym citeproc--number-vars) 88 | ;; OPTIMIZE: This is way too complicated to simply get a filled 89 | ;; numeric value.. 90 | (citeproc-s-fill-left-to-len 91 | (citeproc-number-var-value 92 | (citeproc-var-value var-sym context) var-sym 'numeric context) 93 | 5)) 94 | ((memq var-sym citeproc--date-vars) 95 | (citeproc-sort--date-var-key var-sym context)) 96 | ((memq var-sym citeproc--name-vars) 97 | (citeproc-sort--name-var-key var-sym context)) 98 | (t (citeproc-rt-to-plain (citeproc-var-value var-sym context))))) 99 | (let ((new-context (citeproc-context--create 100 | :vars (citeproc-context-vars context) 101 | :macros (citeproc-context-macros context) 102 | :terms (citeproc-context-terms context) 103 | :date-text (citeproc-context-date-text context) 104 | :date-numeric (citeproc-context-date-numeric context) 105 | :opts (nconc global-attrs (citeproc-context-opts context)) 106 | :mode (citeproc-context-mode context) 107 | :render-mode 'sort 108 | :render-year-suffix nil))) 109 | (citeproc-macro-output-as-text macro new-context))))) 110 | 111 | (defun citeproc-sort--compare-keys (k1 k2 &optional desc) 112 | "Return 1, 0 or -1 depending on the sort-order of keys K1 and K2. 113 | If optional DESC is non-nil then reverse the comparison for 114 | descending sort." 115 | (cond ((string-collate-equalp k1 k2) 0) 116 | ((s-blank? k1) -1) 117 | ((s-blank? k2) 1) 118 | (t (* (if (string-collate-lessp k1 k2) 1 -1) 119 | (if desc -1 1))))) 120 | 121 | (defun citeproc-sort--compare-keylists (k1 k2 sort-orders) 122 | "Whether keylist K1 precedes keylist K2 in the sort order. 123 | SORT-ORDERS is a list of sort orders to use (see the bib- and 124 | cite-sort-orders slots of `citeproc-style' for details)." 125 | (citeproc-lib-lex-compare k1 k2 #'citeproc-sort--compare-keys sort-orders)) 126 | 127 | (defun citeproc-sort--render-keys (style var-alist mode) 128 | "Render the sort keys of an item with STYLE and VAR-ALIST. 129 | MODE is either `cite' or `bib'." 130 | (let ((context (citeproc-context-create var-alist style mode 'sort)) 131 | (sort (cl-ecase mode 132 | (cite (citeproc-style-cite-sort style)) 133 | (bib (citeproc-style-bib-sort style))))) 134 | (if sort (funcall sort context) nil))) 135 | 136 | (defun citeproc-itd-update-sortkey (itd style) 137 | "Update the sort key of itemdata ITD for STYLE." 138 | (setf (citeproc-itemdata-sort-key itd) 139 | (citeproc-sort--render-keys style (citeproc-itemdata-varvals itd) 'bib))) 140 | 141 | (defun citeproc-proc-update-sortkeys (proc) 142 | "Update all sort keys of the itemdata in PROC." 143 | (let ((style (citeproc-proc-style proc)) 144 | (itds (citeproc-proc-itemdata proc))) 145 | (maphash (lambda (_id itd) 146 | (citeproc-itd-update-sortkey itd style)) 147 | itds))) 148 | 149 | (defun citeproc-sort-itds-on-citnum (itds) 150 | "Sort itemdata struct list ITDS according to citation number." 151 | (sort itds 152 | (lambda (x y) 153 | (< (string-to-number (citeproc-itd-getvar x 'citation-number)) 154 | (string-to-number (citeproc-itd-getvar y 'citation-number)))))) 155 | 156 | (defun citeproc-sort-itds-on-subbib (itd1 itd2) 157 | "Sort itemdata structs ITD1 ITD2 according to subbib order." 158 | (let ((idx1 (car (citeproc-itemdata-subbib-nos itd1))) 159 | (idx2 (car (citeproc-itemdata-subbib-nos itd2)))) 160 | (and idx1 161 | (or (null idx2) (< idx1 idx2))))) 162 | 163 | (defun citeproc-sort-itds (itds sort-orders) 164 | "Sort the itemdata struct list ITDS according to SORT-ORDERS." 165 | (sort itds 166 | (lambda (x y) 167 | (citeproc-sort--compare-keylists (citeproc-itemdata-sort-key x) 168 | (citeproc-itemdata-sort-key y) 169 | sort-orders)))) 170 | 171 | (defun citeproc-proc-sort-itds (proc) 172 | "Sort the itemdata in PROC." 173 | (let ((is-sorted-bib (citeproc-style-bib-sort (citeproc-proc-style proc))) 174 | (is-filtered (citeproc-proc-filtered-bib-p proc))) 175 | (when (or is-sorted-bib is-filtered) 176 | (let* ((itds (citeproc-sort-itds-on-citnum 177 | (hash-table-values (citeproc-proc-itemdata proc))))) 178 | (when is-sorted-bib 179 | (let ((sort-orders (citeproc-style-bib-sort-orders 180 | (citeproc-proc-style proc)))) 181 | (setq itds (citeproc-sort-itds itds sort-orders)))) 182 | ;; Additionally sort according to subbibliographies if there are filters. 183 | (when is-filtered 184 | (setq itds (sort itds #'citeproc-sort-itds-on-subbib))) 185 | ;; Set the CSL citation-number field according to the sort order. 186 | (--each-indexed itds 187 | (citeproc-itd-setvar it 'citation-number 188 | (number-to-string (1+ it-index)))))))) 189 | 190 | (provide 'citeproc-sort) 191 | 192 | ;;; citeproc-sort.el ends here 193 | -------------------------------------------------------------------------------- /citeproc-test-human.el: -------------------------------------------------------------------------------- 1 | ;; citeproc-test-human.el --- support tests in CSL suite format -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright (C) 2017-2021 András Simonyi 4 | 5 | ;; Author: András Simonyi 6 | 7 | ;; This program is free software; you can redistribute it and/or modify 8 | ;; it under the terms of the GNU General Public License as published by 9 | ;; the Free Software Foundation, either version 3 of the License, or 10 | ;; (at your option) any later version. 11 | 12 | ;; This program is distributed in the hope that it will be useful, 13 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | ;; GNU General Public License for more details. 16 | 17 | ;; You should have received a copy of the GNU General Public License 18 | ;; along with this program. If not, see . 19 | 20 | ;; This file is not part of GNU Emacs. 21 | 22 | ;;; Commentary: 23 | 24 | ;; Functions to create ERT tests from tests in CSL test suite format. The 25 | ;; official tests can be found at 26 | ;; . 27 | 28 | ;;; Code: 29 | 30 | (require 'f) 31 | (require 's) 32 | (require 'json) 33 | (require 'ert) 34 | (require 'string-inflection) 35 | 36 | (require 'citeproc) 37 | 38 | (defvar citeproc-test-human--locale-dir "./test/locales") 39 | 40 | (defun citeproc-test-human--parse-testfile (file) 41 | "Return a parsed form of CSL test FILE." 42 | (let (result 43 | (json-array-type 'list) 44 | (json-key-type 'symbol)) 45 | (with-temp-buffer 46 | (insert-file-contents file) 47 | (goto-char 1) 48 | (setq result (list (cons 'YEAR-SUFF 49 | (re-search-forward "variable=\"year-suffix\"" nil t)))) 50 | (goto-char 1) 51 | (while (re-search-forward ">>=+ \\{1,2\\}\\([[:graph:]]+\\) =+>>" nil t) 52 | (let ((section (intern (buffer-substring (nth 2 (match-data)) 53 | (nth 3 (match-data))))) 54 | (start (1+ (point))) 55 | end) 56 | (re-search-forward "<<=" nil t) 57 | (setq end (- (car (match-data)) 1)) 58 | (push (cons section (pcase section 59 | ('OUTPUT-FORMAT 60 | (intern (buffer-substring-no-properties start end))) 61 | ('CSL (buffer-substring-no-properties start end)) 62 | ((or 'INPUT 'CITATIONS 'CITATION-ITEMS) 63 | (goto-char (- start 1)) (json-read)) 64 | (_ (buffer-substring start end)))) 65 | result)))) 66 | result)) 67 | 68 | (defun citeproc-test-human--create-getter (items) 69 | "Return a getter function for ITEMS. 70 | ITEMS is the parsed representation of the `INPUT' section of a 71 | CSL test." 72 | (lambda (itemids) 73 | (let (result) 74 | (dolist (item items result) 75 | (let ((id (citeproc-s-from-num-or-s (alist-get 'id item)))) 76 | (when (member id itemids) 77 | (push (cons id item) result))))))) 78 | 79 | (defun citeproc-test-human--proc-from-style (style parsed-input) 80 | "Create a processor from STYLE and PARSED-INPUT." 81 | (citeproc-create style 82 | (citeproc-test-human--create-getter parsed-input) 83 | (citeproc-locale-getter-from-dir citeproc-test-human--locale-dir))) 84 | 85 | (defun citeproc-test-human--proc-from-testfile (file) 86 | "Create an (itemless) processor from a test FILE." 87 | (let ((style-string (alist-get 'CSL (citeproc-test-human--parse-testfile file))) 88 | (locale-getter (citeproc-locale-getter-from-dir citeproc-test-human--locale-dir))) 89 | (citeproc-create style-string nil locale-getter))) 90 | 91 | (defun citeproc-test-human--parse-citation (ct-desc &optional cites-only) 92 | "Parse test citations description CT-DESC. 93 | Return a list of citation structures. If CITES-ONLY is non-nil 94 | then the input is list of cites." 95 | (if cites-only 96 | (citeproc-citation-create 97 | :cites (-map #'citeproc-test-human--normalize-cite ct-desc)) 98 | (let ((citation-info (car ct-desc))) 99 | (let-alist (alist-get 'properties citation-info) 100 | (citeproc-citation-create 101 | :cites (-map #'citeproc-test-human--normalize-cite 102 | (alist-get 'citationItems citation-info)) 103 | :note-index .noteIndex 104 | :mode (citeproc-lib-intern .mode) 105 | :capitalize-first .capitalize-first 106 | :suppress-affixes .suppress-affixes 107 | :ignore-et-al .ignore-et-al))))) 108 | 109 | (defun citeproc-test-human--normalize-cite (cite) 110 | "Normalize a test CITE." 111 | (--map (let ((val (cdr it))) 112 | (if (numberp val) (cons (car it) (number-to-string val)) it)) 113 | cite)) 114 | 115 | (defun citeproc-test-human--run-parsed (parsed) 116 | "Run the parsed CSL test PARSED. 117 | Return the resulting output." 118 | (-let* (((&alist 'CSL style 119 | 'INPUT input 120 | 'MODE mode 121 | 'CITATION-ITEMS citation-items 122 | 'CITATIONS citations 123 | 'OUTPUT-FORMAT output-format) 124 | parsed) 125 | (output-format (or output-format 'csl-test)) 126 | (proc (citeproc-test-human--proc-from-style style input))) 127 | (--each input 128 | (citeproc-proc-put-item-by-id proc 129 | (citeproc-s-from-num-or-s (alist-get 'id it)))) 130 | (when (string= mode "citation") 131 | (cond 132 | (citation-items 133 | (citeproc-append-citations (--map (citeproc-test-human--parse-citation it t) 134 | citation-items) 135 | proc)) 136 | (citations 137 | (citeproc-append-citations (mapcar #'citeproc-test-human--parse-citation citations) 138 | proc)) 139 | (t (citeproc-append-citations (list (citeproc-test-human--parse-citation input t)) 140 | proc)))) 141 | (let ((output (if (string= mode "citation") 142 | (citeproc-render-citations proc output-format 143 | (when (eq 'csl-test output-format) 144 | 'no-links)) 145 | (car (citeproc-render-bib proc output-format 'no-links))))) 146 | (if (string= mode "citation") (s-join "\n" output) output)))) 147 | 148 | (defun citeproc-test-human--expected-from-parsed (parsed) 149 | "Return the expected output of parsed CSL test PARSED." 150 | (let ((expected (alist-get 'RESULT parsed))) 151 | (if (or (string= (s-left 5 expected) "..[0]") 152 | (string= (s-left 5 expected) ">>[0]")) 153 | (s-join "\n" (--map (substring it 6) 154 | (split-string expected "\n"))) 155 | expected))) 156 | 157 | (defun citeproc-test-human-create-from-file (file expected-fails &optional name-prefix) 158 | "Create an ERT test from a CSL test FILE. 159 | If optional NAME-PREFIX is non-nil then it is added the name of 160 | the created test after the obligatory `citeproc'." 161 | (let* ((parsed (citeproc-test-human--parse-testfile file)) 162 | (expected (citeproc-test-human--expected-from-parsed parsed)) 163 | (file-name (f-filename file)) 164 | (test-name (intern 165 | (concat "citeproc-" 166 | (if name-prefix (concat name-prefix "-") "") 167 | (string-inflection-kebab-case-function 168 | (substring file-name 0 -4))))) 169 | (expected-fail (memq test-name expected-fails))) 170 | (eval `(ert-deftest ,test-name () 171 | :expected-result ,(if expected-fail :failed :passed) 172 | (let ((citeproc-disambiguation-cite-pos 'subsequent)) 173 | (should (string= 174 | ,expected 175 | (citeproc-test-human--run-parsed ',parsed)))))))) 176 | 177 | (defun citeproc-test-human---read-expected-fails (expected-fails-file) 178 | "Read the list of tests expected to fail from EXPECTED-FAILS-FILE." 179 | (let* ((list-as-str (with-temp-buffer 180 | (insert-file-contents expected-fails-file) 181 | (buffer-string))) 182 | (split (split-string list-as-str "\n"))) 183 | (--map (intern it) (butlast split)))) 184 | 185 | (defun citeproc-test-human-create-from-dir (dir &optional 186 | expected-fails-file name-prefix) 187 | "Create all CSL tests from DIR. 188 | Each file in DIR having the `txt' extension is read as a 189 | human-readable CSL test, and a corresponding ERT test is created. 190 | The created test's name will be constructed by prefixing the 191 | test's filename (without the extension) with `citeproc-'. If the 192 | optional EXPECTED-FAILS-FILE is non-nil then read that file as a 193 | list of tests whose failure is expected. If optional NAME-PREFIX 194 | is non-nil then it is added the names of the created tests after 195 | the obligatory `citeproc'. The file should contain one test-name 196 | per line (together with the `citeproc-' prefix)." 197 | (let ((expected-fails 198 | (if expected-fails-file 199 | (citeproc-test-human---read-expected-fails expected-fails-file) 200 | nil))) 201 | (dolist (test-file (f-glob (concat dir "/*.txt"))) 202 | (citeproc-test-human-create-from-file test-file expected-fails 203 | name-prefix)))) 204 | 205 | (provide 'citeproc-test-human) 206 | 207 | ;;; citeproc-test-human.el ends here 208 | -------------------------------------------------------------------------------- /citeproc-proc.el: -------------------------------------------------------------------------------- 1 | ;;; citeproc-proc.el --- construct and manage citation processors -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright (C) 2017 András Simonyi 4 | 5 | ;; Author: András Simonyi 6 | 7 | ;; This program is free software; you can redistribute it and/or modify 8 | ;; it under the terms of the GNU General Public License as published by 9 | ;; the Free Software Foundation, either version 3 of the License, or 10 | ;; (at your option) any later version. 11 | 12 | ;; This program is distributed in the hope that it will be useful, 13 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | ;; GNU General Public License for more details. 16 | 17 | ;; You should have received a copy of the GNU General Public License 18 | ;; along with this program. If not, see . 19 | 20 | ;; This file is not part of GNU Emacs. 21 | 22 | ;;; Commentary: 23 | 24 | ;; Structure type and functions to construct citation processor objects, add or 25 | ;; clear stored bibliography items, and disambiguate and finalize the rendering 26 | ;; of the stored items. 27 | 28 | ;;; Code: 29 | 30 | (require 'subr-x) 31 | (require 'dash) 32 | (require 'cl-lib) 33 | (require 'queue) 34 | (require 's) 35 | 36 | (require 'citeproc-date) 37 | (require 'citeproc-itemdata) 38 | (require 'citeproc-disamb) 39 | 40 | (cl-defstruct (citeproc-proc (:constructor citeproc-proc--create)) 41 | "Citation processor struct. 42 | STYLE is a `citeproc-style' struct, 43 | GETTER is a bibliography item getter, 44 | ITEMDATA is a hash table that maps itemids to `citeproc-itemdata' 45 | structs, 46 | CITATIONS is a queue containing citations, 47 | NAMES is hash table that maps name alists to ids, 48 | FINALIZED is non-nil iff the processor is finalized 49 | (bibliography items are properly sorted, citation positions are 50 | updated etc), 51 | UNCITED is a list of lists of uncited itemids to be added during 52 | finalization, 53 | BIB-FILTERS is a list of filters defining sub-bibliographies." 54 | style getter itemdata citations names finalized uncited bib-filters) 55 | 56 | (defun citeproc-proc--internalize-name (name proc) 57 | "Find or add name-alist NAME in/to the names stored in PROC. 58 | Return an internalized version which contains the name-id, and is 59 | sorted." 60 | (let* ((sorted (sort name (lambda (x y) 61 | (string< (car x) (car y))))) 62 | (names (citeproc-proc-names proc)) 63 | (val (gethash sorted names))) 64 | (cons (cons 'name-id 65 | (or val (puthash sorted (hash-table-count names) names))) 66 | sorted))) 67 | 68 | (defconst citeproc-proc--nonstd-csl-vars-alist 69 | '((shortTitle . title-short) (journalAbbreviation . container-title-short)) 70 | "Alist mapping non-standard citeproc.js vars to their standard CSL peers.") 71 | 72 | (defun citeproc-proc--internalize-item (proc item) 73 | "Return the internal form of a CSL json ITEM for PROC." 74 | (let* (label 75 | page-first 76 | (result 77 | (--map 78 | (let* ((orig-var (car it)) 79 | (var (-if-let (mapped (alist-get orig-var 80 | citeproc-proc--nonstd-csl-vars-alist)) 81 | mapped 82 | orig-var)) 83 | (value (citeproc-proc--parse-csl-var-val (cdr it) var proc))) 84 | (pcase var 85 | ('page (-when-let (page-first-match (s-match "[[:digit:]]+" value)) 86 | (setq page-first (car page-first-match)))) 87 | ('label (setq label t))) 88 | (cons var value)) 89 | item))) 90 | (when page-first (push (cons 'page-first page-first) result)) 91 | (unless label (push (cons 'label "page") result)) 92 | ;; Generate the editor-translator variable if needed 93 | ;; (required by CSL 1.02) 94 | (when-let* (((null (alist-get 'editor-translator result))) 95 | (editor (alist-get 'editor result)) 96 | (translator (alist-get 'translator result)) 97 | ((string= (alist-get 'name-id editor) 98 | (alist-get 'name-id translator)))) 99 | (push (cons 'editor-translator editor) result)) 100 | result)) 101 | 102 | (defun citeproc-proc--put-item (proc item itemid &optional uncited) 103 | "Put parsed csl-json ITEM with ITEMID into PROC. 104 | Return the added itemdata structure." 105 | (let* ((int-vars (citeproc-proc--internalize-item proc item)) 106 | (itemdata (citeproc-itemdata-create :varvals int-vars :uncited uncited))) 107 | (citeproc-proc-put-itd-put itemid itemdata proc) 108 | (citeproc-itd-setvar itemdata 'citation-number 109 | (number-to-string (hash-table-count 110 | (citeproc-proc-itemdata proc)))) 111 | (setf (citeproc-proc-finalized proc) nil) 112 | itemdata)) 113 | 114 | (defun citeproc-proc-put-item-by-id (proc itemid) 115 | "Put item with ITEMID into the itemlist of PROC. 116 | Return the itemdata struct that was added." 117 | (let ((item (cdar (funcall (citeproc-proc-getter proc) 118 | (list itemid))))) 119 | (citeproc-proc--put-item proc 120 | (or item `((unprocessed-with-id . ,itemid))) 121 | itemid))) 122 | 123 | (defun citeproc-proc-put-items-by-id (proc itemids) 124 | "Add items with ITEMIDS into the itemlist of PROC." 125 | (let* ((received (funcall (citeproc-proc-getter proc) itemids)) 126 | ;; OPTIMIZE: putting the received items into the original order could/should be 127 | ;; made more efficient 128 | (items (--map (cons it (assoc-default it received)) 129 | itemids))) 130 | (cl-loop for (itemid . item) in items do 131 | (citeproc-proc--put-item proc 132 | (or item `((unprocessed-with-id . ,itemid))) 133 | itemid)))) 134 | 135 | (defun citeproc-proc-put-itd-put (id data proc) 136 | "Put the DATA of item with ID in processor PROC." 137 | (let ((itemdata (citeproc-proc-itemdata proc))) 138 | (puthash id data itemdata))) 139 | 140 | (defun citeproc-proc-process-uncited (proc) 141 | "Add uncited items to the itemdata in PROC." 142 | (when-let ((unciteds (citeproc-proc-uncited proc))) 143 | (let* ((itemids (cl-delete-duplicates (apply #'append unciteds)))) 144 | (when (member "*" itemids) 145 | (setq itemids (funcall (citeproc-proc-getter proc) 'itemids))) 146 | (let* ((itemdata (citeproc-proc-itemdata proc)) 147 | (new-ids (--remove (gethash it itemdata) itemids)) 148 | (id-items (funcall (citeproc-proc-getter proc) new-ids))) 149 | (pcase-dolist (`(,id . ,item) id-items) 150 | (citeproc-proc--put-item 151 | proc 152 | (or item `((unprocessed-with-id . ,id))) 153 | id t)))))) 154 | 155 | (defun citeproc-proc-delete-occurrence-info (proc) 156 | "Remove all itemdata occurrence info from PROC." 157 | (maphash (lambda (_ itd) 158 | (setf (citeproc-itemdata-occurred-before itd) nil)) 159 | (citeproc-proc-itemdata proc))) 160 | 161 | (defun citeproc-proc--parse-csl-json-name (rep) 162 | "Parse the json representation REP of a csl name variable." 163 | (if-let ((literal (alist-get 'literal rep))) 164 | (list (cons 'family (citeproc-s-smart-apostrophes literal))) 165 | (let ((filtered (-remove (lambda (x) (eq (car x) 'isInstitution)) rep))) 166 | (--map (cons 167 | (car it) 168 | (let ((text-field (cdr it))) 169 | (if (stringp text-field) 170 | (citeproc-s-smart-apostrophes text-field) 171 | text-field))) 172 | filtered)))) 173 | 174 | (defun citeproc-proc--parse-csl-var-val (rep var proc) 175 | "Parse the json representation REP of csl variable VAR. 176 | VAR is a csl variable as symbol; 177 | REP is its value in standard csl json representation as parsed by 178 | the Emacs `json' library; 179 | PROC is the target citeproc-processor of the internal representation. 180 | Return the PROC-internal representation of REP." 181 | (cond ((memq var citeproc--name-vars) 182 | (--map (citeproc-proc--internalize-name 183 | (citeproc-proc--parse-csl-json-name it) 184 | proc) 185 | rep)) 186 | ((memq var citeproc--date-vars) 187 | (citeproc-date-parse rep)) 188 | ;;FIXME: We handle here the id... do we need it in the itemdata at all? 189 | ((or (memq var citeproc--number-vars) (eq 'id var)) 190 | (citeproc-s-from-num-or-s rep)) 191 | ((stringp rep) 192 | (let* ((w-aposts (citeproc-s-smart-apostrophes rep)) 193 | (rt (citeproc-rt-from-str w-aposts))) 194 | (if (s-contains-p "\"" rep) 195 | (let* ((terms (citeproc-style-terms (citeproc-proc-style proc))) 196 | (oq (citeproc-term-text-from-terms "open-quote" terms)) 197 | (cq (citeproc-term-text-from-terms "close-quote" terms))) 198 | (citeproc-rt-change-case 199 | rt (lambda (x) (citeproc-s-smart-quotes x oq cq)))) 200 | rt))) 201 | (t rep))) 202 | 203 | (defun citeproc-proc-disamb (proc) 204 | "Disambiguate the items stored in PROC." 205 | (let* ((cite-opts (citeproc-style-cite-opts (citeproc-proc-style proc))) 206 | (name (string= "true" (alist-get 'disambiguate-add-names cite-opts))) 207 | (given (string= "true" (alist-get 'disambiguate-add-givenname cite-opts))) 208 | (yearsuff (string= "true" (alist-get 'disambiguate-add-year-suffix cite-opts)))) 209 | (citeproc-disamb-itds (hash-table-values (citeproc-proc-itemdata proc)) 210 | (citeproc-proc-style proc) 211 | name given yearsuff))) 212 | 213 | (defun citeproc-proc-byte-compile (proc) 214 | "Byte-compile all lambdas in PROC." 215 | (let* ((style (citeproc-proc-style proc)) 216 | (bib-sort (citeproc-style-bib-sort style)) 217 | (cite-sort (citeproc-style-cite-sort style))) 218 | (setf (citeproc-style-macros style) 219 | (--map (cons (car it) (byte-compile (cdr it))) 220 | (citeproc-style-macros style)) 221 | (citeproc-style-cite-layout style) 222 | (byte-compile (citeproc-style-cite-layout style)) 223 | (citeproc-style-bib-layout style) 224 | (byte-compile (citeproc-style-bib-layout style))) 225 | (when bib-sort (setf (citeproc-style-bib-sort style) (byte-compile bib-sort))) 226 | (when cite-sort (setf (citeproc-style-cite-sort style) (byte-compile cite-sort))))) 227 | 228 | (defun citeproc-proc-filtered-bib-p (proc) 229 | "Return whether PROC has nontrivial filters" 230 | (let ((filters (citeproc-proc-bib-filters proc))) 231 | (and filters (not (equal filters '(nil)))))) 232 | 233 | (defun citeproc-proc-max-offset (itds) 234 | "Return the maximal first field width of bibitems in ITDS. 235 | ITDS should be the value of the itemdata field of a citeproc-proc 236 | structure." 237 | (cl-loop for itd being the hash-values of itds 238 | when (listp (citeproc-itemdata-rawbibitem itd)) maximize 239 | (length (citeproc-rt-to-plain (cadr (citeproc-itemdata-rawbibitem itd)))))) 240 | 241 | (provide 'citeproc-proc) 242 | 243 | ;;; citeproc-proc.el ends here 244 | -------------------------------------------------------------------------------- /citeproc-disamb.el: -------------------------------------------------------------------------------- 1 | ;;; citeproc-disamb.el --- disambiguate ambiguous cites -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright (C) 2017 András Simonyi 4 | 5 | ;; Author: András Simonyi 6 | 7 | ;; This program is free software; you can redistribute it and/or modify 8 | ;; it under the terms of the GNU General Public License as published by 9 | ;; the Free Software Foundation, either version 3 of the License, or 10 | ;; (at your option) any later version. 11 | 12 | ;; This program is distributed in the hope that it will be useful, 13 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | ;; GNU General Public License for more details. 16 | 17 | ;; You should have received a copy of the GNU General Public License 18 | ;; along with this program. If not, see . 19 | 20 | ;; This file is not part of GNU Emacs. 21 | 22 | ;;; Commentary: 23 | 24 | ;; Functions to disambiguate cites of different bibliography items that would 25 | ;; have the same rendering. Disambiguation steps (e.g., adding more names, 26 | ;; expanding names, adding year-suffixes) are performed according to the 27 | ;; disambiguation rules specified by the CSL style in use. 28 | 29 | ;;; Code: 30 | 31 | (require 'dash) 32 | (require 'cl-lib) 33 | (require 'subr-x) 34 | 35 | (require 'citeproc-itemdata) 36 | 37 | (defun citeproc-itd-inc-disamb-level (key itd type) 38 | "Increment the disambiguation level of KEY in itemdata ITD. 39 | TYPE is either `add-names' or `show-given-names.'" 40 | (let ((vv (citeproc-itemdata-varvals itd))) 41 | (if (alist-get type vv) 42 | (let* ((cur-level (alist-get key (alist-get type vv))) 43 | (new-level (if cur-level (1+ cur-level) 1))) 44 | (setf (alist-get key (alist-get type vv)) new-level)) 45 | (push `(,type . ((,key . 1))) (citeproc-itemdata-varvals itd)))) 46 | (setf (citeproc-itemdata-rc-uptodate itd) nil)) 47 | 48 | (defun citeproc-itd-add-name (itd style &optional _first-step) 49 | "Perform an add-name disambig. step on itemdata ITD with STYLE. 50 | FIRST-STEP is ignored -- it is there to get the same signature as 51 | the other two disamb. step functions. Return nil if no disambiguation 52 | could be performed and t otherwise. Disambiguation is performed 53 | from left to right: an item is attempted to be expanded only if 54 | no previous items to the left could be." 55 | (let* ((vars (citeproc-itd-namevars itd style)) 56 | (cite (citeproc-itd-plain-cite itd style)) 57 | (vv (citeproc-itemdata-varvals itd)) 58 | (levels (alist-get 'add-names vv)) 59 | (remaining-vars (if levels (memq (caar levels) vars) vars)) 60 | (success nil)) 61 | (while (and (not success) remaining-vars) 62 | (citeproc-itd-inc-disamb-level (car remaining-vars) itd 'add-names) 63 | (if (string= cite (citeproc-itd-plain-cite itd style)) 64 | (pop remaining-vars) 65 | (setq success t))) 66 | success)) 67 | 68 | (defun citeproc-itd-add-given (itd style &optional first-step) 69 | "Perform an add-given disambig. step on itemdata ITD with STYLE. 70 | Unless FIRST-STEP is non-nil, remove the last previously added 71 | given name if the last added given name is shown in its entirety. 72 | Return nil if no disambig. step could be performed and t 73 | otherwise." 74 | (let* ((nids (citeproc-itd-nameids itd style)) 75 | (cite (citeproc-itd-plain-cite itd style)) 76 | (vv (citeproc-itemdata-varvals itd)) 77 | (levels (alist-get 'show-given-names vv)) 78 | (remaining-nids (if levels (memq (caar levels) nids) nids)) 79 | (success nil)) 80 | (while (and (not success) remaining-nids) 81 | (let* ((current-nid (car remaining-nids)) 82 | (vv (citeproc-itemdata-varvals itd)) 83 | (levels (alist-get 'show-given-names vv)) 84 | (current-level (alist-get current-nid levels))) 85 | (if (and current-level (>= current-level 2)) 86 | (pop remaining-nids) 87 | (citeproc-itd-inc-disamb-level current-nid itd 'show-given-names) 88 | (unless (string= cite (citeproc-itd-plain-cite itd style)) 89 | (setq success t) 90 | (unless (or first-step current-level) 91 | (let ((ls (alist-get 'show-given-names vv))) 92 | (setf (alist-get 'show-given-names vv) 93 | (cons (car ls) (cddr ls)))) 94 | (setf (citeproc-itemdata-rc-uptodate itd) nil)))))) 95 | success)) 96 | 97 | (defun citeproc-itd-addgiven-with-addname (itd style &optional first-step) 98 | "Perform a combined disambig. step on itemdata ITD with STYLE. 99 | If FIRST-STEP is non-nil then (i) add a new name even if the last 100 | add-given step showed only initials, (ii) don't remove the 101 | previously added given name. Return nil if no disambig. step 102 | could be performed and t otherwise." 103 | (let* ((vv (citeproc-itemdata-varvals itd)) 104 | (gn (alist-get 'show-given-names vv)) 105 | (success nil) 106 | (remaining-names t)) 107 | (if (and (not first-step) gn (= 1 (cdar gn)) (citeproc-itd-add-given itd style)) 108 | t 109 | (while (and (not success) remaining-names) 110 | (let ((nids (citeproc-itd-nameids itd style))) 111 | (if (citeproc-itd-add-name itd style) 112 | (let* ((new-nids (citeproc-itd-nameids itd style)) 113 | (new-nid (car (cl-set-difference new-nids nids)))) 114 | ;;next sexp is to direct the add-given function to the just added name 115 | (when first-step 116 | (setf (alist-get new-nid 117 | (alist-get 'show-given-names 118 | (citeproc-itemdata-varvals itd))) 119 | 0)) 120 | (when (citeproc-itd-add-given itd style first-step) 121 | (setq success t))) 122 | (setq remaining-names nil)))) 123 | success))) 124 | 125 | (defun citeproc-disamb--different-cites-p (itds style) 126 | "Whether some itemdata in ITDS have different cites with STYLE." 127 | (--any-p (not (string= (citeproc-itd-plain-cite it style) 128 | (citeproc-itd-plain-cite (car itds) style))) 129 | (cdr itds))) 130 | 131 | (defun citeproc-disamb--with-method (itds style disamb-fun) 132 | "Disambiguate itemdatas in ITDS for STYLE with DISAMB-FUN. 133 | Return t if the disambiguation was (at least partially) 134 | successful and nil otherwise." 135 | (let ((orig-settings (copy-tree (citeproc-disamb--settings itds))) 136 | success 137 | (first-step t)) 138 | (while (and (not success) 139 | (--all-p (funcall disamb-fun it style first-step) itds)) 140 | (setq first-step nil) 141 | (when (citeproc-disamb--different-cites-p itds style) 142 | (setq success t))) 143 | (unless success 144 | (citeproc-disamb--restore-settings itds orig-settings)) 145 | success)) 146 | 147 | (defun citeproc-disamb--settings (itds) 148 | "Return a list with the disamb settings of ITDS." 149 | (--map (cons (citeproc-itd-getvar it 'add-names) 150 | (citeproc-itd-getvar it 'show-given-names)) 151 | itds)) 152 | 153 | (defun citeproc-disamb--restore-settings (itds settings) 154 | "Restore the disamb settings of ITDS from SETTINGS. 155 | SETTINGS should have the structure produced by citeproc--disamb-settings." 156 | (cl-loop for itd in itds 157 | for (add-names-val . show-given-val) in settings do 158 | (citeproc-itd-setvar itd 'add-names add-names-val) 159 | (citeproc-itd-setvar itd 'show-given-names show-given-val))) 160 | 161 | (defun citeproc-disamb--num-to-yearsuffix (n) 162 | "Return year-suffix no. N (starting from 0)." 163 | (cond ((< n 26) 164 | (char-to-string (+ 97 n))) 165 | ((< n 702) 166 | (let* ((rem (% n 26)) 167 | (d (/ (- n rem) 26))) 168 | (concat (char-to-string (+ 96 d)) 169 | (char-to-string (+ 97 rem))))) 170 | (t (error "Number too large to convert into a year-suffix")))) 171 | 172 | (defun citeproc-disamb--add-yearsuffix (itds _style) 173 | "Disambiguate itemdata in ITDS by adding year suffices. 174 | Return t (for the sake of consistency with other disamb methods)." 175 | (--each-indexed (--sort (< (string-to-number (citeproc-itd-getvar it 'citation-number)) 176 | (string-to-number (citeproc-itd-getvar other 'citation-number))) 177 | itds) 178 | (citeproc-itd-setvar it 'year-suffix (citeproc-disamb--num-to-yearsuffix it-index)) 179 | (setf (citeproc-itemdata-rc-uptodate it) nil)) 180 | t) 181 | 182 | (defun citeproc-disamb--set-fields (itds) 183 | "Disambiguate ITDS by setting their disambiguate fields." 184 | (--each itds 185 | (citeproc-itd-setvar it 'disambiguate t))) 186 | 187 | (defun citeproc-disamb-amb-itds (itds style name given yearsuff) 188 | "Disambiguate ITDS ambigous for STYLE with the given methods. 189 | NAME, GIVEN and YEARSUFF are generalized booleans specifying 190 | whether or not the add-name, show-given or add-year-suffix 191 | disambiguation methods should be used. Return t if the 192 | disambiguation was (at least partially) successful, nil 193 | otherwise." 194 | (or (and name (citeproc-disamb--with-method itds style 'citeproc-itd-add-name)) 195 | (and given (citeproc-disamb--with-method itds style 'citeproc-itd-add-given)) 196 | (and name given 197 | (citeproc-disamb--with-method itds style 'citeproc-itd-addgiven-with-addname)) 198 | (progn 199 | (citeproc-disamb--set-fields itds) 200 | (citeproc-disamb--different-cites-p itds style)) 201 | (and yearsuff 202 | (citeproc-disamb--add-yearsuffix itds style) 203 | (citeproc-disamb--different-cites-p itds style)))) 204 | 205 | (defun citeproc-amb-itds (itds style) 206 | "Return a list of ambigous sets in ITDS for STYLE. 207 | The returned value is a (possibly empty) list of lists." 208 | (let* ((sorted (-sort (lambda (x y) 209 | (string< (citeproc-itd-plain-cite x style) 210 | (citeproc-itd-plain-cite y style))) 211 | itds)) 212 | (result nil) 213 | (remaining (cdr sorted)) 214 | (act (car sorted)) 215 | (act-list (list act)) 216 | (ambig nil)) 217 | (while remaining 218 | (let ((next (car remaining))) 219 | (if (string= (citeproc-itd-plain-cite act style) 220 | (citeproc-itd-plain-cite next style)) 221 | (progn 222 | (push next act-list) 223 | (setq ambig t)) 224 | (when ambig (push act-list result)) 225 | (setq act-list (list next) 226 | act next 227 | ambig nil)) 228 | (pop remaining))) 229 | (when ambig (push act-list result)) 230 | result)) 231 | 232 | (defun citeproc-disamb-itds (itds style name given yearsuff) 233 | "Disambiguate itemdatas in list ITDS for STYLE. 234 | NAME, GIVEN and YEARSUFF are generalized booleans specifying 235 | whether or not the add-name, show-given or add-year-suffix 236 | disambiguation methods should be used." 237 | (let ((amb-itds (citeproc-amb-itds itds style))) 238 | (while amb-itds 239 | (let ((act-set (pop amb-itds))) 240 | (citeproc-disamb-amb-itds act-set style name given yearsuff) 241 | (when (citeproc-disamb--different-cites-p act-set style) 242 | (-when-let (new-ambs (citeproc-amb-itds act-set style)) 243 | (setq amb-itds (nconc new-ambs amb-itds)))))))) 244 | 245 | (provide 'citeproc-disamb) 246 | 247 | ;;; citeproc-disamb.el ends here 248 | -------------------------------------------------------------------------------- /citeproc-s.el: -------------------------------------------------------------------------------- 1 | ;;; citeproc-s.el --- citeproc-el string functions -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright (C) 2017 András Simonyi 4 | 5 | ;; Author: András Simonyi 6 | 7 | ;; This program is free software; you can redistribute it and/or modify 8 | ;; it under the terms of the GNU General Public License as published by 9 | ;; the Free Software Foundation, either version 3 of the License, or 10 | ;; (at your option) any later version. 11 | 12 | ;; This program is distributed in the hope that it will be useful, 13 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | ;; GNU General Public License for more details. 16 | 17 | ;; You should have received a copy of the GNU General Public License 18 | ;; along with this program. If not, see . 19 | 20 | ;; This file is not part of GNU Emacs. 21 | 22 | ;;; Commentary: 23 | 24 | ;; String utility functions for citeproc-el. 25 | 26 | ;;; Code: 27 | 28 | (require 'thingatpt) 29 | (require 's) 30 | (require 'compat) 31 | 32 | (defun citeproc-s-camelcase-p (s) 33 | "Return whether string S is in camel case." 34 | (let ((case-fold-search nil)) 35 | (and (< 1 (length s)) 36 | (s-matches-p "[[:upper:]]" (substring s 1)) 37 | (s-matches-p "[[:lower:]]" s)))) 38 | 39 | (defun citeproc-s-fill-copy (s1 s2) 40 | "Return a copy of string S1 filled by characters from string S2. 41 | If string S1 is shorter than string S2 then prepend enough 42 | characters from to beginning of S2 to the beginning of a copy of 43 | S2 to make their length equal, and return the filled copy." 44 | (if (>= (length s1) (length s2)) s1 45 | (concat (substring s2 0 (- (length s2) (length s1))) s1))) 46 | 47 | (defun citeproc-s-fill-left-to-len (s len &optional char) 48 | "Fill string S to length LEN with CHAR from left." 49 | (let ((len-s (length s)) 50 | (char (or char ?0))) 51 | (if (>= len-s len) s 52 | (concat (make-string (- len len-s) char) s)))) 53 | 54 | (defun citeproc-s-nil-or-s-to-num (s) 55 | "Convert S, which is a string or nil to a number. 56 | A nil value is converted to 0." 57 | (if s (string-to-number s) 0)) 58 | 59 | (defun citeproc-s-from-num-or-s (x) 60 | "Return the content of string or number X as a number." 61 | (if (numberp x) (number-to-string x) x)) 62 | 63 | (defun citeproc-s-content (s) 64 | "Return the string content of string or symbol or nil S. 65 | The string content of nil is defined as \"\"." 66 | (pcase s 67 | ((\` nil) "") 68 | ((pred symbolp) (symbol-name s)) 69 | (_ s))) 70 | 71 | (defun citeproc-s-slice-by-matches (s regexp &optional start annot) 72 | "Slice S up at the boundaries of each REGEXP match. 73 | Optionally start from index START. Matches are also included 74 | among the slices, but all zero-length slices are omitted. If 75 | optional ANNOT is non-nil then slices are given as (S . B) cons 76 | cells where S is the slice string, while B is nil if the S slice 77 | is a separating REGEXP match and t otherwise." 78 | (unless start (setq start 0)) 79 | (save-match-data 80 | (let ((begin (string-match regexp s start))) 81 | (if begin 82 | (let ((end (match-end 0))) 83 | (if (and (= begin start) (= end start)) 84 | (citeproc-s-slice-by-matches s regexp (1+ start) annot) 85 | (let ((result (citeproc-s-slice-by-matches (substring s end) 86 | regexp 0 annot))) 87 | (unless (= begin end) 88 | (let ((slice (substring s begin end))) 89 | (push (if annot (list slice) slice) result))) 90 | (unless (= 0 begin) 91 | (let ((slice (substring s 0 begin))) 92 | (push (if annot (cons slice t) slice) result))) 93 | result))) 94 | (list (if annot (cons s t) s)))))) 95 | 96 | (defun citeproc-s-tail (s length) 97 | "Return the closing substring of string S with length LENGTH. 98 | Return S if LENGTH is nil or not less than the length of S." 99 | (let ((l (length s))) 100 | (if (and length (< length l)) 101 | (substring s (- l length)) 102 | s))) 103 | 104 | (defun citeproc-s-capitalize-first (s) 105 | "Capitalize the first word in string S. 106 | Return the capitalized version of S. If S contains no word or the 107 | first word is not in lowercase then return S." 108 | (if (s-present-p s) 109 | (with-temp-buffer 110 | (insert s) 111 | (goto-char 1) 112 | (forward-word) 113 | (backward-word) 114 | (let ((word (word-at-point))) 115 | (when (s-lowercase-p word) 116 | (capitalize-word 1))) 117 | (buffer-string)) 118 | s)) 119 | 120 | (defun citeproc-s-capitalize-all (s) 121 | "Capitalize all lowercase words in string S. 122 | Return the capitalized version of S. If S contains no word or the 123 | first word is not in lowercase then return S." 124 | (if (s-present-p s) 125 | (with-temp-buffer 126 | (insert s) 127 | (goto-char 1) 128 | (while (forward-word) 129 | (let ((word (word-at-point))) 130 | (when (s-lowercase-p word) 131 | (capitalize-word -1)))) 132 | (buffer-string)) 133 | s)) 134 | 135 | (defun citeproc-s-sentence-case (s) 136 | "Return a sentence-cased version of string S." 137 | (if (s-present-p s) 138 | (with-temp-buffer 139 | (insert s) 140 | (goto-char 1) 141 | (let ((first t)) 142 | (while (forward-word) 143 | (let ((word (word-at-point))) 144 | (cond ((s-uppercase-p word) (capitalize-word -1)) 145 | ((and first (s-lowercase-p word)) (capitalize-word -1)))) 146 | (when first (setq first nil)))) 147 | (buffer-string)) 148 | s)) 149 | 150 | (defun citeproc-s-sentence-case-title (s &optional omit-nocase) 151 | "Return a sentence-cased version of title string S. 152 | If optional OMIT-NOCASE is non-nil then omit the nocase tags from the output." 153 | (if (s-blank-p s) s 154 | (let ((sliced (citeproc-s-slice-by-matches 155 | s "\\(\\|\\|: +[\"'“‘]*[[:alpha:]]\\)")) 156 | (protect-level 0) 157 | (first t) 158 | result) 159 | (dolist (slice sliced) 160 | (push 161 | (pcase slice 162 | ("" (cl-incf protect-level) (if omit-nocase nil slice)) 163 | ("" (cl-decf protect-level) (if omit-nocase nil slice)) 164 | ;; Don't touch the first letter after a colon since it probably 165 | ;; starts a subtitle. 166 | ((pred (string-match-p "^: +[\"'“‘]*[[:alpha:]]")) (setq first nil) slice) 167 | (_ (cond ((< 0 protect-level) (setq first nil) slice) 168 | ((not first) (downcase slice)) 169 | (t (setq first nil) 170 | ;; We upcase the first letter and downcase the rest. 171 | (let ((pos (string-match "[[:alpha:]]" slice))) 172 | (if pos (concat (substring slice 0 pos) 173 | (upcase (substring slice pos (1+ pos))) 174 | (downcase (substring slice (1+ pos)))) 175 | slice)))))) 176 | result)) 177 | (apply #'concat (nreverse result))))) 178 | 179 | (defconst citeproc-s-english-stopwords 180 | '("a" "according to" "across" "afore" "after" "against" "ahead of" "along" "alongside" 181 | "amid" "amidst" "among" "amongst" "an" "and" "anenst" "apart from" "apropos" 182 | "around" "as" "as regards" "aside" "astride" "at" "athwart" "atop" "back to" 183 | "barring" "because of" "before" "behind" "below" "beneath" "beside" "besides" 184 | "between" "beyond" "but" "by" "c" "ca" "circa" "close to" "d'" "de" "despite" "down" 185 | "due to" "during" "et" "except" "far from" "for" "forenenst" "from" "given" "in" 186 | "inside" "instead of" "into" "lest" "like" "modulo" "near" "next" "nor" "of" "off" 187 | "on" "onto" "or" "out" "outside of" "over" "per" "plus" "prior to" "pro" "pursuant 188 | to" "qua" "rather than" "regardless of" "sans" "since" "so" "such as" "than" 189 | "that of" "the" "through" "throughout" "thru" "thruout" "till" "to" "toward" "towards" 190 | "under" "underneath" "until" "unto" "up" "upon" "v." "van" "versus" "via" "vis-à-vis" 191 | "von" "vs." "where as" "with" "within" "without" "yet")) 192 | 193 | (defun citeproc-s-title-case (s) 194 | "Return a title-cased version of string S." 195 | (if (s-present-p s) 196 | (with-temp-buffer 197 | (insert s) 198 | (goto-char 1) 199 | (let ((first t) 200 | after-colon) 201 | (while (forward-word) 202 | (let ((word (word-at-point))) 203 | (cond ((and (not (or first after-colon)) 204 | (member (downcase word) citeproc-s-english-stopwords) 205 | ;; Don't downcase A before a period: 206 | (or (not (string= word "A")) 207 | (= (point) (point-max)) 208 | (/= (char-after) ?.))) 209 | (downcase-word -1)) 210 | ((s-lowercase-p word) 211 | (capitalize-word -1)))) 212 | (when first (setq first nil)) 213 | (when (< (point) (point-max)) 214 | (setq after-colon (or (= (char-after) ?:) 215 | (= (char-after) ?.)))))) 216 | (buffer-string)) 217 | s)) 218 | 219 | (defun citeproc-s-smart-quotes (s oq cq) 220 | "Replace dumb quotes in string S with smart ones OQ and CQ. 221 | OQ is the opening quote, CQ is the closing quote to use." 222 | (with-temp-buffer 223 | (insert s) 224 | (goto-char 1) 225 | (while (search-forward "\"" nil 1) 226 | (let ((w-a-p (word-at-point))) 227 | (delete-char -1) 228 | (insert (if w-a-p oq cq)))) 229 | (buffer-string))) 230 | 231 | (defun citeproc-s-replace-all-seq (s replacements) 232 | "Make replacements in S according to REPLACEMENTS sequentially. 233 | REPLACEMENTS is an alist with (FROM . TO) elements." 234 | (let ((result s)) 235 | (pcase-dolist (`(,from . ,to) replacements) 236 | (setq result (string-replace from to result))) 237 | result)) 238 | 239 | (defun citeproc-s-replace-all-sim (s regex replacements) 240 | "Replace all matches of REGEX in S according to REPLACEMENTS simultaneously. 241 | REPLACEMENTS is an alist with (FROM . TO) elements." 242 | (replace-regexp-in-string regex 243 | (lambda (match) (cdr (assoc-string match replacements))) 244 | s t t)) 245 | 246 | (defun citeproc-s-smart-apostrophes (s) 247 | "Replace dumb apostophes in string S with smart ones. 248 | The replacement character used is the unicode character `modifier 249 | letter apostrophe'." 250 | (string-replace "'" "ʼ" (string-replace "’" "ʼ" s))) 251 | 252 | (defconst citeproc-s--cull-spaces-alist 253 | '((" " . " ") (";;" . ";") ("..." . ".") (",," . ",") (".." . ".")) 254 | "Alist describing replacements for space and punct culling.") 255 | 256 | (defconst citeproc-s--cull-spaces-alist-rx 257 | (regexp-opt (mapcar #'car citeproc-s--cull-spaces-alist))) 258 | 259 | (defun citeproc-s-cull-spaces-puncts (s) 260 | "Replace unnecessary characters with delete chars in string S." 261 | (let ((result (citeproc-s-replace-all-seq s citeproc-s--cull-spaces-alist))) 262 | (dolist (match-rep '(("\\([:;!?]\\):" . "\\1") 263 | ("\\([:.;!?]\\)\\." . "\\1") 264 | ("\\([:;!]\\)!" . "!") 265 | ("\\([:;?]\\)\\?" . "?") 266 | ("\\.\\([”’‹›«»]\\)\\." . ".\\1") 267 | (",\\([”’‹›«»]\\)," . ",\\1")) 268 | result) 269 | (setq result (replace-regexp-in-string (car match-rep) 270 | (cdr match-rep) 271 | result))))) 272 | 273 | (provide 'citeproc-s) 274 | 275 | ;;; citeproc-s.el ends here 276 | -------------------------------------------------------------------------------- /test/expected_fails.lst: -------------------------------------------------------------------------------- 1 | citeproc-suite-affix-comma-after-quote 2 | citeproc-suite-affix-moving-punctuation 3 | citeproc-suite-affix-space-with-quotes 4 | citeproc-suite-affix-with-commas 5 | citeproc-suite-bugreports-automatically-delete-items-fails 6 | citeproc-suite-bugreports-caps-after-one-word-prefix 7 | citeproc-suite-bugreports-chicago-author-date-looping 8 | citeproc-suite-bugreports-creeping-add-names 9 | citeproc-suite-bugreports-demo-page-full-cite-cruft-on-subsequent 10 | citeproc-suite-bugreports-env-and-urb 11 | citeproc-suite-bugreports-french-apostrophe 12 | citeproc-suite-bugreports-ikey-one 13 | citeproc-suite-bugreports-move-punctuation-inside-quotes-for-locator 14 | citeproc-suite-bugreports-no-case-escape 15 | citeproc-suite-bugreports-no-title 16 | citeproc-suite-bugreports-number-affix-escape 17 | citeproc-suite-bugreports-number-in-macro-with-vertical-align 18 | citeproc-suite-bugreports-overwrite-citation-items 19 | citeproc-suite-bugreports-parse-name 20 | citeproc-suite-bugreports-single-quote-xml 21 | citeproc-suite-bugreports-small-caps-escape 22 | citeproc-suite-collapse-author-collapse-no-date-sorted 23 | citeproc-suite-collapse-chicago-after-collapse 24 | citeproc-suite-collapse-citation-number-ranges-insert 25 | citeproc-suite-date-date-no-date-no-test 26 | citeproc-suite-date-empty-strings 27 | citeproc-suite-date-in-press 28 | citeproc-suite-date-other-alone 29 | citeproc-suite-date-other-with-date 30 | citeproc-suite-date-range-delimiter 31 | citeproc-suite-date-season-range1 32 | citeproc-suite-date-season-range2 33 | citeproc-suite-date-season-range3 34 | citeproc-suite-date-season-substitute-in-group 35 | citeproc-suite-date-string 36 | citeproc-suite-date-text-form-yeardate-year-range-open 37 | citeproc-suite-date-various-invalid-dates 38 | citeproc-suite-date-year-suffix-implicit-with-no-date 39 | citeproc-suite-date-year-suffix-with-no-date 40 | citeproc-suite-decorations-nested-quotes-inner-reverse 41 | citeproc-suite-decorations-no-normal-without-decoration 42 | citeproc-suite-decorations-simple-flip-flop 43 | citeproc-suite-disambiguate-all-names-generally 44 | citeproc-suite-disambiguate-all-names-simple-sequence 45 | citeproc-suite-disambiguate-all-names-with-initials-generally 46 | citeproc-suite-disambiguate-based-on-subsequent-form-with-backref2 47 | citeproc-suite-disambiguate-by-cite-incremental2 48 | citeproc-suite-disambiguate-citation-label-default 49 | citeproc-suite-disambiguate-citation-label-in-data 50 | citeproc-suite-disambiguate-disambiguation-hang 51 | citeproc-suite-disambiguate-incremental-extra-text 52 | citeproc-suite-disambiguate-initialize-with-but-no-disambiguation 53 | citeproc-suite-disambiguate-primary-name-generally 54 | citeproc-suite-disambiguate-primary-name-with-initials-limited-to-primary 55 | citeproc-suite-disambiguate-to-initial-only 56 | citeproc-suite-disambiguate-trigraph 57 | citeproc-suite-disambiguate-year-collapse-with-institution 58 | citeproc-suite-disambiguate-year-suffix-fifty-two-entries 59 | citeproc-suite-disambiguate-year-suffix-fifty-two-entries-by-cite 60 | citeproc-suite-disambiguate-year-suffix-with-et-al-subsequent 61 | citeproc-suite-display-author-as-heading 62 | citeproc-suite-etal-use-zero-first 63 | citeproc-suite-flipflop-apostrophes 64 | citeproc-suite-flipflop-boldface-node-level-markup 65 | citeproc-suite-flipflop-complete-cite-in-prefix 66 | citeproc-suite-flipflop-italics-flipped 67 | citeproc-suite-flipflop-italics-simple 68 | citeproc-suite-flipflop-italics-with-ok 69 | citeproc-suite-flipflop-italics-with-ok-and-textcase 70 | citeproc-suite-flipflop-leading-single-quote 71 | citeproc-suite-flipflop-orphan-quote 72 | citeproc-suite-flipflop-quotes-in-field-not-on-node 73 | citeproc-suite-flipflop-quotes-node-level-markup 74 | citeproc-suite-flipflop-single-before-colon 75 | citeproc-suite-flipflop-small-caps 76 | citeproc-suite-fullstyles-a-bd-nt 77 | citeproc-suite-fullstyles-chicago-author-date-simple 78 | citeproc-suite-integration-delete-name 79 | citeproc-suite-integration-disambiguate-add-givenname1 80 | citeproc-suite-integration-disambiguate-add-givenname2 81 | citeproc-suite-integration-duplicate-item 82 | citeproc-suite-integration-duplicate-item2 83 | citeproc-suite-integration-first-reference-note-number-position-change 84 | citeproc-suite-integration-ibid-on-insert 85 | citeproc-suite-integration-year-suffix-on-off-on 86 | citeproc-suite-label-collapsed-page-number-plural-detection 87 | citeproc-suite-label-editor-translator1 88 | citeproc-suite-label-editor-translator2 89 | citeproc-suite-label-name-label-through-substitute 90 | citeproc-suite-label-plural-with-localized-ampersand 91 | citeproc-suite-locale-empty-plus-override-date 92 | citeproc-suite-locale-non-existent-locale-def 93 | citeproc-suite-locale-overload-with-empty-string 94 | citeproc-suite-locator-simple-locators 95 | citeproc-suite-locator-tricky-entry-for-plurals 96 | citeproc-suite-locator-with-leading-space 97 | citeproc-suite-magic-capitalize-first-occurring-term 98 | citeproc-suite-magic-citation-label-in-bibliography 99 | citeproc-suite-magic-citation-label-in-citation 100 | citeproc-suite-magic-name-suffix-no-comma 101 | citeproc-suite-magic-name-suffix-with-comma 102 | citeproc-suite-magic-punctuation-in-quote-nested 103 | citeproc-suite-magic-superscript-chars 104 | citeproc-suite-magic-suppress-layout-delimiter-if-prefix-comma 105 | citeproc-suite-magic-term-capitalization-with-prefix 106 | citeproc-suite-name-articular-name-as-sort-order 107 | citeproc-suite-name-articular-with-comma 108 | citeproc-suite-name-articular-with-comma-name-as-sort-order 109 | citeproc-suite-name-asian-glyphs 110 | citeproc-suite-name-celts-and-toffs-crowded-initials 111 | citeproc-suite-name-celts-and-toffs-spaced-initials 112 | citeproc-suite-name-cite-group-delimiter-with-year-suffix-collapse 113 | citeproc-suite-name-cite-group-delimiter-with-year-suffix-collapse2 114 | citeproc-suite-name-cite-group-delimiter-with-year-suffix-collapse3 115 | citeproc-suite-name-delimiter-after-inverted 116 | citeproc-suite-name-editor-translator-same-empty-term 117 | citeproc-suite-name-et-al-with-combined 118 | citeproc-suite-name-hebrew-and 119 | citeproc-suite-name-hyphenated-non-dropping-particle1 120 | citeproc-suite-name-hyphenated-non-dropping-particle2 121 | citeproc-suite-name-in-text-markup-initialize 122 | citeproc-suite-name-in-text-markup-normalize-initials 123 | citeproc-suite-name-initials-initialize-false 124 | citeproc-suite-name-initials-initialize-false-empty 125 | citeproc-suite-name-initials-initialize-false-period 126 | citeproc-suite-name-initials-initialize-false-period-space 127 | citeproc-suite-name-initials-initialize-true 128 | citeproc-suite-name-initials-initialize-true-empty 129 | citeproc-suite-name-initials-initialize-true-period 130 | citeproc-suite-name-initials-initialize-true-period-space 131 | citeproc-suite-name-long-abbreviation 132 | citeproc-suite-name-lowercase-surname-suffix 133 | citeproc-suite-name-namepart-affixes 134 | citeproc-suite-name-namepart-affixes-name-as-sort-order 135 | citeproc-suite-name-namepart-affixes-name-as-sort-order-demote-non-dropping-particle 136 | citeproc-suite-name-only-givenname 137 | citeproc-suite-name-parse-names 138 | citeproc-suite-name-parsed-dropping-particle-with-apostrophe 139 | citeproc-suite-name-parsed-non-dropping-particle-with-apostrophe 140 | citeproc-suite-name-particle-caps3 141 | citeproc-suite-name-particles-demote-non-dropping-never 142 | citeproc-suite-name-split-initials 143 | citeproc-suite-name-subsequent-author-substitute-single-field 144 | citeproc-suite-name-substitute-on-names-span-group-span-fail 145 | citeproc-suite-name-substitute-on-names-span-names-span-fail 146 | citeproc-suite-name-substitute-partial-each 147 | citeproc-suite-name-with-non-breaking-space 148 | citeproc-suite-nameorder-long-name-as-sort-demote-display-and-sort 149 | citeproc-suite-nameorder-long-name-as-sort-demote-never 150 | citeproc-suite-number-limit-ordinals-to-day-one 151 | citeproc-suite-number-new-ordinals-edition 152 | citeproc-suite-number-new-ordinals-with-gender-change 153 | citeproc-suite-number-ordinal-spacing 154 | citeproc-suite-number-plain-hyphen-or-en-dash-always-plural 155 | citeproc-suite-number-separate-ordinal-namespaces 156 | citeproc-suite-page-chicago16 157 | citeproc-suite-position-first-true-only-once 158 | citeproc-suite-position-ibid-in-text 159 | citeproc-suite-position-ibid-with-locator 160 | citeproc-suite-position-ibid-with-multiple-solo-cites-in-backref 161 | citeproc-suite-position-ibid-with-prefix-full-stop 162 | citeproc-suite-position-if-ibid-with-locator-is-true-then-ibid-is-true 163 | citeproc-suite-position-near-note-false 164 | citeproc-suite-position-reset-note-numbers 165 | citeproc-suite-punctuation-french-orthography 166 | citeproc-suite-punctuation-full-monty-quotes-in 167 | citeproc-suite-quotes-punctuation-with-inner-quote 168 | citeproc-suite-sort-bibliography-citation-number-descending-via-composite-macro 169 | citeproc-suite-sort-bibliography-citation-number-descending-via-macro 170 | citeproc-suite-sort-case-insensitive-bibliography 171 | citeproc-suite-sort-case-insensitive-citation 172 | citeproc-suite-sort-citation-number-primary-descending-via-macro-bibliography 173 | citeproc-suite-sort-citation-number-primary-descending-via-macro-citation 174 | citeproc-suite-sort-citation-number-primary-descending-via-variable-bibliography 175 | citeproc-suite-sort-citation-number-primary-descending-via-variable-citation 176 | citeproc-suite-sort-conditional-macro-dates 177 | citeproc-suite-sort-drop-name-label-in-sort 178 | citeproc-suite-sort-family-only 179 | citeproc-suite-sort-leading-a 180 | citeproc-suite-sort-leading-apostrophe-on-name-particle 181 | citeproc-suite-sort-name-variable 182 | citeproc-suite-sort-omitted-bib-ref-mixed-numeric-style 183 | citeproc-suite-sort-omitted-bib-ref-non-numeric-style 184 | citeproc-suite-sort-quotes 185 | citeproc-suite-sort-range-unaffected 186 | citeproc-suite-sort-separate-authors-and-others 187 | citeproc-suite-sort-with-and-in-one-entry 188 | citeproc-suite-substitute-substitute-only-once-term 189 | citeproc-suite-substitute-substitute-only-once-term-empty 190 | citeproc-suite-substitute-suppress-ordinary-variable 191 | citeproc-suite-testers-first-auto-generated-zotero-plugin-test 192 | citeproc-suite-testers-second-auto-generated-zotero-plugin-test 193 | citeproc-suite-textcase-implicit-nocase 194 | citeproc-suite-textcase-in-quotes 195 | citeproc-suite-textcase-last-char 196 | citeproc-suite-textcase-locale-unicode 197 | citeproc-suite-textcase-no-space-before-apostrophe 198 | citeproc-suite-textcase-non-english-chars 199 | citeproc-suite-textcase-repeated-title-bug 200 | citeproc-suite-textcase-sentence-capitalization 201 | citeproc-suite-textcase-skip-name-particles-in-title-case 202 | citeproc-suite-textcase-stop-word-before-hyphen 203 | citeproc-suite-variables-container-title-short 204 | citeproc-suite-variables-container-title-short2 205 | citeproc-suite-variables-title-short-on-short-title-no-title-condition 206 | citeproc-suite-bugreports-sorted-ieee-italics-fail 207 | citeproc-suite-bugreports-undefined-in-name3 208 | citeproc-suite-date-negative-date-sort 209 | citeproc-suite-date-negative-date-sort-via-macro-on-year-month-only 210 | citeproc-suite-magic-subsequent-author-substitute-not-fooled 211 | citeproc-suite-punctuation-delimiter-with-strip-periods-and-substitute3 212 | citeproc-suite-bugreports-sorted-ieee-italics-fail 213 | citeproc-suite-bugreports-undefined-in-name3 214 | citeproc-suite-date-negative-date-sort 215 | citeproc-suite-date-negative-date-sort-via-macro-on-year-month-only 216 | citeproc-suite-magic-subsequent-author-substitute-not-fooled 217 | citeproc-suite-punctuation-delimiter-with-strip-periods-and-substitute3 218 | --------------------------------------------------------------------------------