diff options
Diffstat (limited to 'Master/texmf-dist/tex/latex/citation-style-language/citation-style-language.sty')
-rw-r--r-- | Master/texmf-dist/tex/latex/citation-style-language/citation-style-language.sty | 729 |
1 files changed, 455 insertions, 274 deletions
diff --git a/Master/texmf-dist/tex/latex/citation-style-language/citation-style-language.sty b/Master/texmf-dist/tex/latex/citation-style-language/citation-style-language.sty index 117e9c844ab..546ac13eeca 100644 --- a/Master/texmf-dist/tex/latex/citation-style-language/citation-style-language.sty +++ b/Master/texmf-dist/tex/latex/citation-style-language/citation-style-language.sty @@ -1,46 +1,40 @@ % -% Copyright (C) 2021 Zeping Lee +% Copyright (c) 2021-2022 Zeping Lee +% Released under the MIT License. +% Repository: https://github.com/zepinglee/citeproc-lua % \NeedsTeXFormat{LaTeX2e} + \RequirePackage{expl3} \RequirePackage{xparse} + \ProvidesExplPackage {citation-style-language} {2022-01-22} {v0.1.0} {Citation Style Language for LaTeX} -% \msg_new:nnn { citation-style-language } { require-luatex } -% { LuaTeX~ is~ required~ for~ `citation-style-language'~ package. } -% \sys_if_engine_luatex:F { \msg_fatal:nn { citation-style-language } { require-luatex } } - -\sys_if_engine_luatex:T - { \lua_now:n { csl = require("csl") } } - \RequirePackage { filehook } \RequirePackage { url } -\cs_new:Npn \csl_incompatible_package:n #1 - { - \AtBeginOfPackageFile* { #1 } - { \msg_error:nnn { citation-style-language } { incompatible-package } { #1 } } - } +% Check incompatible packages \msg_new:nnn { citation-style-language } { incompatible-package } { The~ `#1'~ package~ is~ incompatible~ with~ `citeproc'. } -\csl_incompatible_package:n { babelbib } -\csl_incompatible_package:n { backref } -\csl_incompatible_package:n { biblatex } -\csl_incompatible_package:n { bibtopic } -\csl_incompatible_package:n { bibunits } -\csl_incompatible_package:n { chapterbib } -\csl_incompatible_package:n { cite } -\csl_incompatible_package:n { citeref } -\csl_incompatible_package:n { inlinebib } -\csl_incompatible_package:n { jurabib } -\csl_incompatible_package:n { mcite } -\csl_incompatible_package:n { mciteplus } -\csl_incompatible_package:n { multibib } -\csl_incompatible_package:n { natbib } -\csl_incompatible_package:n { splitbib } +\cs_new_protected:Npn \__csl_load_check:n #1 + { + \AtBeginOfPackageFile* {#1} + { \msg_error:nnn { citation-style-language } { incompatible-package } {#1} } + } + +\clist_map_function:nN + { + babelbib , backref , biblatex , bibtopic , bibunits , chapterbib , + cite , citeref , inlinebib , jurabib , mcite , mciteplus , + multibib , natbib , splitbib + } + \__csl_load_check:n + +\sys_if_engine_luatex:T + { \lua_now:n { csl = require("csl") } } \NewDocumentCommand \cslsetup { m } @@ -50,243 +44,237 @@ \DeclareDocumentCommand \cite { o o m } - { - \IfValueTF { #2 } - { \csl_cite:nnn { #1 } { #2 } { #3 } } - { - \IfValueTF { #1 } - { \csl_cite:nnn { } { #1 } { #3 } } - { \csl_cite:nnn { } { } { #3 } } - } - } + { \__csl_cite:nnn {#1} {#2} {#3} } -% % multicite command -% \DeclareDocumentCommand \cites { o o m } +% \cites[⟨prenote⟩][⟨postnote⟩]{⟨key⟩}...[⟨prenote⟩][⟨postnote⟩]{⟨key⟩} +\NewDocumentCommand \cites { } + { \__csl_cites: } -\DeclareDocumentCommand \nocite { m } - { - \ifx \@begindocumenthook \@undefined \else - \exp_after:wN \AtBeginDocument - \fi - { - \if@filesw - \iow_now:Nn \@auxout - { \citation { { nocite } { #1 } { } } } - \fi - } - \sys_if_engine_luatex:T - { \lua_now:n { csl.nocite("#1") } } -} - - -\tl_new:N \l__csl_citation_tl -\tl_new:N \l__csl_citation_id_tl -\tl_new:N \l__csl_cite_items_tl -\tl_new:N \l__csl_note_index_tl -\tl_new:N \l__csl_citation_info_tl +\seq_new:N \l__csl_cite_keys_seq +\seq_new:N \l__csl_cite_items_seq -\cs_new:Npn \csl_cite:nnn #1#2#3 +\cs_new:Npn \__csl_cite:nnn #1#2#3 { - \csl_process_citation_id:n { #3 } - \csl_process_cite_items:nnn { #1 } { #2 } { #3 } - \exp_args:NV \csl_process_note_index:n \l__csl_citation_id_tl - \tl_set:Nx \l__csl_citation_info_tl - { - { \l__csl_citation_id_tl } - { \l__csl_cite_items_tl } - { \l__csl_note_index_tl } - } - \if@filesw - { - \iow_now:Nx \@auxout - { \exp_not:N \citation { \l__csl_citation_info_tl } } - } - \fi - \tl_clear:N \l__csl_citation_tl - \tl_if_exist:cTF { g__csl_citation_ \l__csl_citation_id_tl _tl } - { - \exp_args:Nv \csl_print_defined_citation:n - { g__csl_citation_ \l__csl_citation_id_tl _tl } - } - { - \bool_if:NTF \l__csl_engine_initialized_bool - { - \tl_set:Nx \l__csl_citation_tl - { \lua_now:e { csl.cite("\l__csl_citation_info_tl") } } - } - { - \exp_args:Nx \csl_print_undefined_citation:n - { \clist_use:Nn \l__csl_keys_clist { ,~ } } - } - } - } - -\cs_new:Npn \csl_print_undefined_citation:n #1 - { - \tl_set:Nn \l__csl_citation_tl { [ \textbf { #1 } ] } - \G@refundefinedtrue - \exp_args:Nnnx \msg_warning:nnn { citation-style-language } { citation / undefined } { #1 } - \group_begin: - \reset@font [ \textbf { #1 } ] - \group_end: + \seq_clear:N \l__csl_cite_keys_seq + \seq_clear:N \l__csl_cite_items_seq + \__csl_process_cite_items:nnn {#1} {#2} {#3} + \__csl_make_citation:NN \l__csl_cite_keys_seq \l__csl_cite_items_seq } -\cs_new:Npn \csl_print_defined_citation:n #1 - { - \csl_print_defined_citation_aux:nn #1 - } -\cs_new:Npn \csl_print_defined_citation_aux:nn #1#2 +\cs_new:Npn \__csl_cites: { - \tl_set:Nn \l__csl_citation_tl { #2 } - \tl_if_eq:nnTF { #1 } { note } - { \footnote { #2 } } - { #2 } + \seq_clear:N \l__csl_cite_keys_seq + \seq_clear:N \l__csl_cite_items_seq + \__csl_next_cites:nnn } - -\msg_new:nnn { citation-style-language } { citation / undefined } +\NewDocumentCommand \__csl_next_cites:nnn { o o g } { - Citation~ `#1'~ on~ page~ \thepage \space undefined~ \msg_line_context: . + \tl_if_novalue:nTF {#3} + { \__csl_make_citation:NN \l__csl_cite_keys_seq \l__csl_cite_items_seq } + { + \__csl_process_cite_items:nnn {#1} {#2} {#3} + \__csl_next_cites:nnn + } } -\clist_new:N \l__csl_keys_clist -\tl_new:N \l__csl_normalized_keys_tl - -% \csl_process_citation_id:n { <cite item ids> } -% It sets the `\l__csl_citation_id_tl` `ITEM-1,ITEM-2@4`. -\cs_new:Npn \csl_process_citation_id:n #1 +\cs_new:Npn \__csl_process_cite_items:nnn #1#2#3 + % #1,#2: prenote/postnote, #3: keys { - \clist_set:Nn \l__csl_keys_clist { #1 } - \tl_set:Nx \l__csl_normalized_keys_tl - { \clist_use:Nn \l__csl_keys_clist { , } } - \int_if_exist:cF { g__csl_citation_count_ \l__csl_normalized_keys_tl _int } + \tl_if_novalue:nTF {#2} { - \int_gzero_new:c - { g__csl_citation_count_ \l__csl_normalized_keys_tl _int } - } - \int_gincr:c { g__csl_citation_count_ \l__csl_normalized_keys_tl _int } - \tl_set:Nx \l__csl_citation_id_tl - { - \l__csl_normalized_keys_tl @ - \int_use:c { g__csl_citation_count_ \l__csl_normalized_keys_tl _int } + \tl_if_novalue:nTF {#1} + { \__csl_process_cite_items_aux:nnn { } { } {#3} } + { \__csl_process_cite_items_aux:nnn { } {#1} {#3} } } + { \__csl_process_cite_items_aux:nnn {#1} {#2} {#3} } } - -\tl_new:N \l__csl_cite_item_tl - -% `{citationID}{{id={id1},{}},{}}{<noteIndex>}` -\cs_new:Npn \csl_process_cite_items:nnn #1#2#3 +\cs_new:Npn \__csl_process_cite_items_aux:nnn #1#2#3 + % #1: prenote, #2: postnote, #3: keys + % Return: "{id={ITEM-1},{locator=6},...}, {id={ITEM-2},...}, ..." { - \tl_clear:N \l__csl_cite_items_tl - \clist_map_inline:nn { #3 } + \int_zero:N \l_tmpa_int + \clist_map_inline:nn {#3} { - \tl_if_empty:NTF \l__csl_cite_items_tl - { - \csl_process_cite_item:nnn { #1 } { #2 } { ##1 } - \tl_put_right:Nx \l__csl_cite_items_tl { { \l__csl_cite_item_tl } } - } - { - \csl_process_cite_item:nnn { } { } { ##1 } - \tl_put_right:Nx \l__csl_cite_items_tl { , { \l__csl_cite_item_tl } } - } + \int_incr:N \l_tmpa_int + \seq_put_right:Nn \l__csl_cite_keys_seq {##1} + \int_compare:nNnTF { \l_tmpa_int } = { 1 } + { \__csl_process_cite_item:nnn {#1} {#2} {##1} } + { \__csl_process_cite_item:nnn { } { } {##1} } } } \prop_new:N \l__csl_cite_item_prop - -\keys_define:nn { csl / cite-item } - { - prefix .prop_put:N = \l__csl_cite_item_prop, - suffix .prop_put:N = \l__csl_cite_item_prop, - locator .prop_put:N = \l__csl_cite_item_prop, - label .prop_put:N = \l__csl_cite_item_prop, - suppress-author .prop_put:N = \l__csl_cite_item_prop, - author-only .prop_put:N = \l__csl_cite_item_prop, - uris .prop_put:N = \l__csl_cite_item_prop, - book .code:n = { \csl_set_locator:nn { book } { #1 } } , - chapter .code:n = { \csl_set_locator:nn { chapter } { #1 } } , - column .code:n = { \csl_set_locator:nn { column } { #1 } } , - figure .code:n = { \csl_set_locator:nn { figure } { #1 } } , - folio .code:n = { \csl_set_locator:nn { folio } { #1 } } , - issue .code:n = { \csl_set_locator:nn { issue } { #1 } } , - line .code:n = { \csl_set_locator:nn { line } { #1 } } , - note .code:n = { \csl_set_locator:nn { note } { #1 } } , - opus .code:n = { \csl_set_locator:nn { opus } { #1 } } , - page .code:n = { \csl_set_locator:nn { page } { #1 } } , - paragraph .code:n = { \csl_set_locator:nn { paragraph } { #1 } } , - part .code:n = { \csl_set_locator:nn { part } { #1 } } , - section .code:n = { \csl_set_locator:nn { section } { #1 } } , - sub-verbo .code:n = { \csl_set_locator:nn { sub-verbo } { #1 } } , - verse .code:n = { \csl_set_locator:nn { verse } { #1 } } , - volume .code:n = { \csl_set_locator:nn { volume } { #1 } } , - } - -\cs_new:Npn \csl_set_locator:nn #1#2 - { - \prop_put:Nnn \l__csl_cite_item_prop { label } { #1 } - \prop_put:Nnn \l__csl_cite_item_prop { locator } { #2 } - } - \tl_new:N \l__csl_prefix_tl \tl_new:N \l__csl_suffix_tl -% \csl_process_cite_item:nnn { <prenote> } { <postnote> } { <item ID> } -% return: `id={ITEM},locator={42},label={page}` -\cs_new:Npn \csl_process_cite_item:nnn #1#2#3 +\cs_new:Npn \__csl_process_cite_item:nnn #1#2#3 + % #1: prenote, #2: postnote, #3: key + % Save "{id={ITEM},locator={42},label={page}}" into \l__csl_cite_items_seq { \prop_clear:N \l__csl_cite_item_prop - \prop_put:Nnn \l__csl_cite_item_prop { id } { #3 } - \tl_if_empty:nF { #1 } + \prop_put:Nnn \l__csl_cite_item_prop { id } {#3} + \tl_if_empty:nF {#1} { - \tl_set:Nn \l__csl_prefix_tl { #1 } + \tl_set:Nn \l__csl_prefix_tl {#1} \tl_put_right:NV \l__csl_prefix_tl \l__csl_prefix_separator_tl \prop_put:NnV \l__csl_cite_item_prop { prefix } { \l__csl_prefix_tl } } - \tl_if_in:nnTF { #2 } { = } + \tl_if_in:nnTF {#2} { = } { - \keys_set:nn { csl / cite-item } { #2 } + \keys_set:nn { csl / cite-item } {#2} } { - \tl_if_empty:nF { #2 } + \tl_if_empty:nF {#2} { - \regex_match:nnTF { \d+ } { #2 } - { \csl_set_locator:nn { page } { #2 } } + \regex_match:nnTF { \d+ } {#2} + { \__csl_set_locator:nn { page } {#2} } { - \tl_set:Nn \l__csl_suffix_tl { #2 } + \tl_set:Nn \l__csl_suffix_tl {#2} \tl_put_left:NV \l__csl_suffix_tl \l__csl_suffix_separator_tl \prop_put:NnV \l__csl_cite_item_prop { suffix } { \l__csl_suffix_tl } } } } - \tl_clear:N \l__csl_cite_item_tl + \seq_clear:N \l_tmpa_seq \prop_map_inline:Nn \l__csl_cite_item_prop + { \seq_put_right:Nn \l_tmpa_seq { ##1 = {##2} } } + \seq_put_right:Nx \l__csl_cite_items_seq + { { \seq_use:Nn \l_tmpa_seq { , } } } + } + +\cs_new:Npn \__csl_set_locator:nn #1#2 + { + \prop_put:Nnn \l__csl_cite_item_prop { label } {#1} + \prop_put:Nnn \l__csl_cite_item_prop { locator } {#2} + } + +\keys_define:nn { csl / cite-item } + { + prefix .prop_put:N = \l__csl_cite_item_prop, + suffix .prop_put:N = \l__csl_cite_item_prop, + locator .prop_put:N = \l__csl_cite_item_prop, + label .prop_put:N = \l__csl_cite_item_prop, + suppress-author .prop_put:N = \l__csl_cite_item_prop, + author-only .prop_put:N = \l__csl_cite_item_prop, + uris .prop_put:N = \l__csl_cite_item_prop, + act .code:n = { \__csl_set_locator:nn { act } {#1} } , + appendix .code:n = { \__csl_set_locator:nn { appendix } {#1} } , + article-locator .code:n = { \__csl_set_locator:nn { article-locator } {#1} } , + book .code:n = { \__csl_set_locator:nn { book } {#1} } , + canon .code:n = { \__csl_set_locator:nn { canon } {#1} } , + chapter .code:n = { \__csl_set_locator:nn { chapter } {#1} } , + column .code:n = { \__csl_set_locator:nn { column } {#1} } , + elocation .code:n = { \__csl_set_locator:nn { elocation } {#1} } , + equation .code:n = { \__csl_set_locator:nn { equation } {#1} } , + figure .code:n = { \__csl_set_locator:nn { figure } {#1} } , + folio .code:n = { \__csl_set_locator:nn { folio } {#1} } , + issue .code:n = { \__csl_set_locator:nn { issue } {#1} } , + line .code:n = { \__csl_set_locator:nn { line } {#1} } , + note .code:n = { \__csl_set_locator:nn { note } {#1} } , + opus .code:n = { \__csl_set_locator:nn { opus } {#1} } , + page .code:n = { \__csl_set_locator:nn { page } {#1} } , + paragraph .code:n = { \__csl_set_locator:nn { paragraph } {#1} } , + part .code:n = { \__csl_set_locator:nn { part } {#1} } , + rule .code:n = { \__csl_set_locator:nn { rule } {#1} } , + scene .code:n = { \__csl_set_locator:nn { scene } {#1} } , + section .code:n = { \__csl_set_locator:nn { section } {#1} } , + sub-verbo .code:n = { \__csl_set_locator:nn { sub-verbo } {#1} } , + supplement .code:n = { \__csl_set_locator:nn { supplement } {#1} } , + table .code:n = { \__csl_set_locator:nn { table } {#1} } , + timestamp .code:n = { \__csl_set_locator:nn { timestamp } {#1} } , + title-locator .code:n = { \__csl_set_locator:nn { title-locator } {#1} } , + verse .code:n = { \__csl_set_locator:nn { verse } {#1} } , + version .code:n = { \__csl_set_locator:nn { version } {#1} } , + volume .code:n = { \__csl_set_locator:nn { volume } {#1} } , + } + + +\tl_new:N \l__csl_citation_id_tl +\tl_new:N \l__csl_cite_items_tl +\tl_new:N \l__csl_note_index_tl +\tl_new:N \l__csl_citation_info_tl +\tl_new:N \l__csl_citation_tl +\prop_new:N \g__csl_citations_prop + +\cs_new:Npn \__csl_make_citation:NN #1#2 + % #1: \l__csl_cite_keys_seq + % #2: \l__csl_cite_items_seq + { + \__csl_process_citation_id:NN \l__csl_citation_id_tl #1 + \tl_set:Nx \l__csl_cite_items_tl + { \seq_use:Nn #2 { , } } + \exp_args:NNV \__csl_process_note_index:Nn \l__csl_note_index_tl \l__csl_citation_id_tl + \tl_set:Nx \l__csl_citation_info_tl + { + { \l__csl_citation_id_tl } + { \l__csl_cite_items_tl } + { \l__csl_note_index_tl } + } + \exp_args:NV \__csl_write_aux_citation:n \l__csl_citation_info_tl + \prop_get:NVNTF \g__csl_citations_prop \l__csl_citation_id_tl + \l__csl_citation_tl + { \exp_args:NV \__csl_print_citation:n \l__csl_citation_tl } + { + \bool_if:NTF \l__csl_engine_initialized_bool + { + \tl_set:Nx \l__csl_citation_tl + { \lua_now:e { csl.cite("\l__csl_citation_info_tl") } } + } + { + \exp_args:Nx \__csl_print_undefined_citation:n + { \seq_use:Nn \l__csl_cite_keys_seq { ,~ } } + } + } + } + + +\tl_new:N \l__csl_cite_keys_tl +\tl_new:N \l__csl_citation_count_tl +\int_new:N \l__csl_citation_count_int +\prop_new:N \g__csl_citations_count_prop + +\cs_new:Npn \__csl_process_citation_id:NN #1#2 + % #1: \l__csl_citation_id_tl + % #2: \l__csl_cite_keys_seq + % Set \l__csl_citation_id_tl = "ITEM-1,ITEM-2@4". + { + \tl_set:Nx \l__csl_cite_keys_tl + { \seq_use:Nn #2 { , } } + \prop_get:NVNTF \g__csl_citations_count_prop \l__csl_cite_keys_tl + \l__csl_citation_count_tl { - \tl_if_empty:NF \l__csl_cite_item_tl - { \tl_put_right:Nn \l__csl_cite_item_tl { , } } - \tl_put_right:Nn \l__csl_cite_item_tl { ##1 = { ##2 } } + \int_set:Nn \l__csl_citation_count_int { \l__csl_citation_count_tl } + \int_incr:N \l__csl_citation_count_int } + { \int_set_eq:NN \l__csl_citation_count_int \c_one_int } + \prop_gput:NVV \g__csl_citations_count_prop \l__csl_cite_keys_tl + \l__csl_citation_count_int + \tl_set:Nx #1 + { \l__csl_cite_keys_tl @ \int_use:N \l__csl_citation_count_int } } + \int_new:N \l__csl_note_index_int \int_gzero_new:N \g__csl_last_note_index_int \int_gzero_new:N \g__csl_citation_note_count_int -% \csl_process_note_index:nnn { <citation ID> } -\cs_new:Npn \csl_process_note_index:n #1 +\cs_new:Npn \__csl_process_note_index:Nn #1#2 + % #1 \l__csl_note_index_tl + % #2: citationID { \int_set_eq:Nc \l__csl_note_index_int { c@ \@mpfn } - \tl_if_exist:cTF { g__csl_citation_ #1 _tl } + \prop_if_in:NnTF \g__csl_citations_prop {#2} { \int_incr:N \l__csl_note_index_int } { \int_gincr:N \g__csl_citation_note_count_int } \int_add:Nn \l__csl_note_index_int { \g__csl_citation_note_count_int } - \tl_set:Nx \l__csl_note_index_tl - { \int_use:N \l__csl_note_index_int } + \tl_set:Nx #1 { \int_use:N \l__csl_note_index_int } \int_gset_eq:NN \g__csl_last_note_index_int \l__csl_note_index_int \int_compare:nT { \l__csl_note_index_int < \g__csl_last_note_index_int } { @@ -296,6 +284,73 @@ } +\cs_new:Npn \__csl_write_aux_citation:n #1 + % #1: citation info "{<citationID>}{{id=ITEM-1},{id=ITEM-2}}{<noteIndex>}" + { + \if@filesw + \iow_now:Nn \@auxout + { \citation { #1 } } + \fi + } + + +\cs_new:Npn \__csl_print_citation:n #1 + % #1: "{<type>}{<citation text>}" + { \__csl_print_citation_aux:nn #1 } + +\cs_new:Npn \__csl_print_citation_aux:nn #1#2 + % #1: citation type, "in-text" or "note" + % #2: citation text + { + \tl_set:Nn \l__csl_citation_tl {#2} + \tl_if_eq:nnTF {#1} { note } + { \footnote {#2} } + {#2} + } + + +\cs_new:Npn \__csl_print_undefined_citation:n #1 + % #1: keys + { + \tl_set:Nn \l__csl_citation_tl { [ \textbf {#1} ] } + \G@refundefinedtrue + \msg_warning:nnn { citation-style-language } { citation / undefined } {#1} + \group_begin: + \reset@font [ \textbf {#1} ] + \group_end: + } + +\msg_new:nnn { citation-style-language } { citation / undefined } + { Citation~ `#1'~ on~ page~ \thepage \space undefined~ \msg_line_context: . } + + +\DeclareDocumentCommand \nocite { m } + { \__csl_no_cite:n {#1} } + + +\cs_new:Npn \__csl_no_cite:n #1 + { + \__csl_if_preamble:TF + { + \AtBeginDocument + { \__csl_write_aux_citation:n { { nocite } {#1} { } } } + } + { \__csl_write_aux_citation:n { { nocite } {#1} { } } } + \sys_if_engine_luatex:T + { \lua_now:n { csl.nocite("#1") } } +} + + +\prg_new_conditional:Nnn \__csl_if_preamble: { T , F , TF } + { + \if_meaning:w \@begindocumenthook \@undefined + \prg_return_false: + \else + \prg_return_true: + \fi + } + + % Used in aux files to register cite items. \cs_set:Npn \citation #1 { @@ -306,34 +361,20 @@ \cs_new:Npn \cslcite #1#2 { - \bibcite { #1 } { #2 } + \bibcite {#1} {#2} \if@filesw - \iow_now:Nn \@auxout { \bibcite { #1 } { #2 } } + \iow_now:Nn \@auxout { \bibcite {#1} {#2} } \fi } -\cs_set:Npn \bibcite #1#2 - { - \tl_gset:cn { g__csl_citation_ #1 _tl } { #2 } - } +\cs_new:Npn \__csl_bibcite:nn #1#2 + { \prop_gput:Nnn \g__csl_citations_prop {#1} {#2} } -% The `babel` package redefines \bibcite in the \@begindocumenthook. -% This should be disabled. -\AtEndOfPackageFile* { babel } - { - \cs_set_eq:NN \bbl@cite@choice \relax - } +\cs_set_eq:NN \bibcite \__csl_bibcite:nn -\AtEndOfPackageFile* { hyperref } - { - \cs_set:Npn \bibcite #1#2 - { - \tl_gset:cn { g__csl_citation_ #1 _tl } { #2 } - } - } -\NewDocumentCommand \printbibliography { } +\NewDocumentCommand \printbibliography { O { } } { \sys_if_engine_luatex:TF { @@ -349,11 +390,11 @@ \msg_warning:nnx { citation-style-language } { file / non-exist} { \jobname .bbl } } } - { \exp_args:NV \csl_print_bibiliography_tl \l__csl_bibliography_tl } + { \exp_args:NV \__csl_print_bibliography:n \l__csl_bibliography_tl } } } -\cs_new:Npn \csl_print_bibliography_tl #1 +\cs_new:Npn \__csl_print_bibliography:n #1 { \begin { thebibliography } #1 @@ -529,14 +570,14 @@ { \tl_if_empty:NTF \l__csl_style_tl { \tl_set_eq:NN \l__csl_style_tl \g__csl_aux_bibstyle_tl } - { \exp_args:Nx \csl_write_aux_bibstyle:n { \l__csl_style_tl } } + { \exp_args:Nx \__csl_write_aux_bibstyle:n { \l__csl_style_tl } } \clist_if_empty:NTF \l__csl_bib_resources_clist { \clist_set_eq:NN \l__csl_bib_resources_clist \g__csl_aux_bib_files_clist } { - \exp_args:Nx \csl_write_aux_bibdata:n + \exp_args:Nx \__csl_write_aux_bibdata:n { \clist_use:Nn \l__csl_bib_resources_clist { , } } } - \csl_write_aux_csl_options: + \__csl_write_aux_csl_options: \sys_if_engine_luatex:T { \lua_now:e @@ -558,24 +599,24 @@ % of `thebibliography` is stored into \l__csl_bibliography_tl. \group_begin: \RenewDocumentCommand \cslsetup { m } - { \tl_set:Nn \l__csl_bibliography_setup_tl { #1 } } + { \tl_set:Nn \l__csl_bibliography_setup_tl {#1} } \RenewDocumentEnvironment { thebibliography } { m +b } - { \tl_set:Nn \l__csl_bibliography_tl { { #1 } #2 } } + { \tl_set:Nn \l__csl_bibliography_tl { {#1} #2 } } { } \file_if_exist_input:n { \jobname .bbl } \group_end: } -\cs_new:Npn \csl_write_aux_bibstyle:n #1 +\cs_new:Npn \__csl_write_aux_bibstyle:n #1 { \if@filesw - \iow_now:Nn \@auxout { \bibstyle { #1 } } + \iow_now:Nn \@auxout { \bibstyle {#1} } \fi } \clist_new:N \l__csl_options_clist -\cs_new:Nn \csl_write_aux_csl_options: +\cs_new:Npn \__csl_write_aux_csl_options: { \clist_clear:N \l__csl_options_clist % locale @@ -612,40 +653,40 @@ \DeclareDocumentCommand \bibliographystyle { m } { - \ifx \@begindocumenthook \@undefined - \csl_write_aux_bibstyle:n { #1 } - \fi - \tl_set:Nn \l__csl_style_tl { #1 } + \__csl_if_preamble:F + { \__csl_write_aux_bibstyle:n {#1} } + \tl_set:Nn \l__csl_style_tl {#1} } \tl_new:N \g__csl_aux_bibstyle_tl \cs_set:Npn \bibstyle #1 - { \tl_gset:Nn \g__csl_aux_bibstyle_tl { #1 } } + { \tl_gset:Nn \g__csl_aux_bibstyle_tl {#1} } \NewDocumentCommand \addbibresource { o m } - { \clist_put_right:Nn \l__csl_bib_resources_clist { #2 } } + { \clist_put_right:Nn \l__csl_bib_resources_clist {#2} } \clist_new:N \g__csl_aux_bib_files_clist \cs_set:Npn \bibdata #1 - { \clist_gput_right:Nn \g__csl_aux_bib_files_clist { #1 } } + { \clist_gput_right:Nn \g__csl_aux_bib_files_clist {#1} } \DeclareDocumentCommand \bibliography { m } { - \csl_write_aux_bibdata:n { #1 } + \__csl_write_aux_bibdata:n {#1} \printbibliography } -\cs_new:Npn \csl_write_aux_bibdata:n #1 +\cs_new:Npn \__csl_write_aux_bibdata:n #1 { \if@filesw - \iow_now:Nn \@auxout { \bibdata { #1 } } + \iow_now:Nn \@auxout { \bibdata {#1} } \fi } +% Used for debugging and testing \clist_new:N \g__csl_bib_items_clist % For numeric or label-style bibliography @@ -653,39 +694,34 @@ % {\let\protect\noexpand % \immediate % \write\@auxout{\string\bibcite{#2}{#1}}}\fi\ignorespaces} -\cs_new:Npn \csl_lbibitem:nn [#1]#2 +\cs_new:Npn \__csl_lbibitem:nn [#1]#2 { - \clist_gput_right:Nn \g__csl_bib_items_clist { #2 } - \item [ \@biblabel { #1 } \hfill ] \ignorespaces + \clist_gput_right:Nn \g__csl_bib_items_clist {#2} + \item [ \@biblabel {#1} \hfill ] \ignorespaces } -\cs_set_eq:NN \@lbibitem \csl_lbibitem:nn +\cs_set_eq:NN \@lbibitem \__csl_lbibitem:nn % For author-date bibliography % \def\@bibitem#1{\item\if@filesw \immediate\write\@auxout % {\string\bibcite{#1}{\the\value{\@listctr}}}\fi\ignorespaces} -\cs_new:Npn \csl_bibitem:n #1 +\cs_new:Npn \__csl_bibitem:n #1 { - \clist_gput_right:Nn \g__csl_bib_items_clist { #1 } + \clist_gput_right:Nn \g__csl_bib_items_clist {#1} \item [ ] \ignorespaces } -\cs_set_eq:NN \@bibitem \csl_bibitem:n +\cs_set_eq:NN \@bibitem \__csl_bibitem:n -\AtEndOfPackageFile* { hyperref } - { - \cs_gset_eq:NN \@lbibitem \csl_lbibitem:nn - \cs_gset_eq:NN \@bibitem \csl_bibitem:n - } % CSL outputs the whole label thus the brackets are removed from \@biblabel % \def\@biblabel#1{[#1]} -\cs_set:Npn \@biblabel #1 { #1 } +\cs_set:Npn \@biblabel #1 {#1} \cs_if_exist:cTF { chapter } { - \cs_set:Nn \csl_bib_section: + \cs_set:Nn \__csl_bib_section: { - \chapter * + \chapter* { \bibname \@mkboth @@ -695,9 +731,9 @@ } } { - \cs_set:Nn \csl_bib_section: + \cs_set:Nn \__csl_bib_section: { - \section * + \section* { \refname \@mkboth @@ -714,7 +750,7 @@ \dim_new:N \l__csl_bib_hang_dim \skip_new:N \l__csl_bib_item_sep_skip -\cs_new:Npn \csl_set_bib_label_spacing:n #1 +\cs_new:Npn \__csl_set_bib_label_spacing:n #1 { \bool_if:NTF \l__csl_hanging_indent_bool { @@ -723,13 +759,13 @@ \dim_set:Nn \itemindent { - \leftmargin } } { - \settowidth \labelwidth { \@biblabel { #1 } } + \settowidth \labelwidth { \@biblabel {#1} } \dim_set_eq:NN \leftmargin \labelwidth \dim_add:Nn \leftmargin { \labelsep } } } -\cs_new:Nn \csl_set_bib_item_sep: +\cs_new:Npn \__csl_set_bib_item_sep: { \skip_zero:N \parsep \tl_if_empty:NTF \l__csl_bib_item_sep_tl @@ -743,7 +779,7 @@ { \skip_set:Nn \l__csl_bib_item_sep_skip { \l__csl_bib_item_sep_tl } } } -\cs_new:Nn \csl_set_bib_allow_break: +\cs_new:Npn \__csl_set_bib_allow_break: { \sloppy \int_set:Nn \clubpenalty { 4000 } @@ -752,11 +788,10 @@ % \sfcode`\.\@m \frenchspacing } -% TODO: \biburlsetup -\cs_new_eq:NN \csl_set_bib_page_break: \csl_set_bib_allow_break: +\cs_new_eq:NN \__csl_set_bib_page_break: \__csl_set_bib_allow_break: -\cs_new:Nn \csl_set_bib_no_break: +\cs_new:Npn \__csl_set_bib_no_break: { \sloppy \int_set:Nn \interlinepenalty { 5000 } @@ -767,8 +802,117 @@ \frenchspacing } + +% Taken from `biblatex`'s \biburlsetup +% https://github.com/plk/biblatex/blob/dev/tex/latex/biblatex/biblatex.def + +\int_new:N \l__csl_url_big_break_penalty_int +\int_new:N \l__csl_url_break_penalty_int +\int_new:N \l__csl_url_num_penalty_int +\int_new:N \l__csl_url_uc_penalty_int +\int_new:N \l__csl_url_lc_penalty_int + +\int_set:Nn \l__csl_url_big_break_penalty_int { 100 } +\int_set:Nn \l__csl_url_break_penalty_int { 200 } +% Allow linebreaks before numbers and letters. +% Taken from `xurl.sty`. +\int_set:Nn \l__csl_url_num_penalty_int { 9000 } +\int_set:Nn \l__csl_url_uc_penalty_int { 9000 } +\int_set:Nn \l__csl_url_lc_penalty_int { 8000 } + +\muskip_new:N \l__csl_url_big_muskip +\muskip_new:N \l__csl_url_num_muskip +\muskip_new:N \l__csl_url_uc_muskip +\muskip_new:N \l__csl_url_lc_muskip + +\muskip_set:Nn \l__csl_url_big_muskip { 0mu plus 3mu } +\muskip_set:Nn \l__csl_url_num_muskip { 0mu } +\muskip_set:Nn \l__csl_url_uc_muskip { 0mu } +\muskip_set:Nn \l__csl_url_lc_muskip { 0mu } + +\cs_new:Npn \__csl_bib_url_setup: + { + \urlstyle { same } + \muskip_set_eq:NN \Urlmuskip \l__csl_url_big_muskip + \mathchardef \UrlBigBreakPenalty = \l__csl_url_big_break_penalty_int + \mathchardef \UrlBreakPenalty = \l__csl_url_break_penalty_int + % \int_set_eq:NN doesn't work here + % \int_set_eq:NN \UrlBigBreakPenalty \l__csl_url_big_break_penalty_int + % \int_set_eq:NN \UrlBreakPenalty \l__csl_url_break_penalty_int + \tl_set:Nn \UrlBigBreaks { \do \: \do \- } + \tl_set:Nn \UrlBreaks + { + \do \. \do \@ \do \/ \do \\ \do \! \do \_ \do \| \do \; \do \> \do \] + \do \) \do \} \do \, \do \? \do \' \do \+ \do \= \do \# \do \$ \do \& + \do \* \do \^ \do \" + } + \int_compare:nNnT { \l__csl_url_num_penalty_int } > { 0 } + { + \clist_map_inline:nn + { \1 , \2 , \3 , \4 , \5 , \6 , \7 , \8 , \9 , \0 } + { + \tl_put_right:Nn \UrlSpecials + { + \do ##1 + { + \mathchar`##1 + \mskip \l__csl_url_num_muskip + \penalty \l__csl_url_num_penalty_int + } + } + } + } + \int_compare:nNnT { \l__csl_url_uc_penalty_int } > { 0 } + { + \clist_map_inline:nn + { + \A , \B , \C , \D , \E , \F , \G , \H , \I , \J , + \K , \L , \M , \N , \O , \P , \Q , \R , \S , \T , + \U , \V , \W , \X , \Y , \Z + } + { + \tl_put_right:Nn \UrlSpecials + { + \do ##1 + { + \mathchar`##1 + \mskip \l__csl_url_uc_muskip + \penalty \l__csl_url_uc_penalty_int + } + } + } + } + \int_compare:nNnT { \l__csl_url_lc_penalty_int } > { 0 } + { + \clist_map_inline:nn + { + \a , \b , \c , \d , \e , \f , \g , \h , \i , \j , + \k , \l , \m , \n , \o , \p , \q , \r , \s , \t , + \u , \v , \w , \x , \y , \z + } + { + \tl_put_right:Nn \UrlSpecials + { + \do ##1 + { + \mathchar`##1 + \mskip \l__csl_url_lc_muskip + \penalty \l__csl_url_lc_penalty_int + } + } + } + } + \cs_set_eq:NN \do \exp_not:N + } + +% The above code allows linebreaks before numbers and letters. +% This is often the only way to break DOIs. It also allows breaks +% after hyphens and adjusts \Urlmuskip to add some stretchability +% to URLs. + + % It will be used for multi-bibliography. -\cs_new:Nn \csl_reset_bib_format: +\cs_new:Npn \__csl_reset_bib_format: { \keys_set:nn { csl } { hanging-indent = false , @@ -780,7 +924,7 @@ % \newenvironment{thebibliography}[1] \RenewDocumentEnvironment { thebibliography } { m } { - \csl_bib_section: + \__csl_bib_section: \dim_zero:N \parindent \l__csl_bib_preamble_tl \tl_if_eq:NnF \l__csl_line_spacing_tl { 1 } @@ -788,12 +932,13 @@ \l__csl_bib_font_tl \list { } { - \csl_set_bib_label_spacing:n { #1 } - \csl_set_bib_item_sep: + \__csl_set_bib_label_spacing:n {#1} + \__csl_set_bib_item_sep: } \sloppy - \csl_set_bib_page_break: + \__csl_set_bib_page_break: \frenchspacing + \__csl_bib_url_setup: \clist_gclear:N \g__csl_bib_items_clist } { @@ -801,7 +946,43 @@ \tl_set:Nn \@noitemerr { \msg_warning:nnn { citation-style-language } { bibliography / empty } } \endlist - \csl_reset_bib_format: + \__csl_reset_bib_format: + } + + + +% Compatibilities with other packages + +% babel + +% The `babel` package redefines \bibcite in the \@begindocumenthook. +% This should be disabled. +\AtEndOfPackageFile* { babel } + { + \RenewDocumentCommand \nocite { m } + { + % \@safe@activestrue\org@nocite{#1}\@safe@activesfalse + \@safe@activestrue + \__csl_no_cite:n {#1} + \@safe@activesfalse + } + \cs_set_eq:NN \bibcite \__csl_bibcite:nn + \cs_set_eq:NN \bbl@cite@choice \relax + \cs_set_eq:NN \@bibitem \__csl_bibitem:n } + +% hyperref + +% The hyperref package also patches \bibcite but it cannot provide hyperlinks +% when used with csl. +\AtEndOfPackageFile* { hyperref } + { + \cs_set_eq:NN \bibcite \__csl_bibcite:nn + \cs_set_eq:NN \Hy@bibcite \bibcite + \cs_gset_eq:NN \@lbibitem \__csl_lbibitem:nn + \cs_gset_eq:NN \@bibitem \__csl_bibitem:n + } + + \endinput |