diff options
author | Karl Berry <karl@freefriends.org> | 2024-03-24 20:05:18 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2024-03-24 20:05:18 +0000 |
commit | 9614ef3a79ae0b4ca0a708ed89b0d4ea26cb313a (patch) | |
tree | f799fc13d822d4295e636f717d9e1e703dedeaac /Master/texmf-dist/tex | |
parent | 22fdc4d76bff6dae082b913ce1b578a8c82a7174 (diff) |
multifootnote (24mar24)
git-svn-id: svn://tug.org/texlive/trunk@70745 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex')
-rw-r--r-- | Master/texmf-dist/tex/latex/multifootnote/multifootnote.sty | 440 |
1 files changed, 408 insertions, 32 deletions
diff --git a/Master/texmf-dist/tex/latex/multifootnote/multifootnote.sty b/Master/texmf-dist/tex/latex/multifootnote/multifootnote.sty index 2c8d5e45ae1..02bf24b0232 100644 --- a/Master/texmf-dist/tex/latex/multifootnote/multifootnote.sty +++ b/Master/texmf-dist/tex/latex/multifootnote/multifootnote.sty @@ -1,5 +1,5 @@ %% -%% Copyright (C) 2022 by Jinwen XU +%% Copyright (C) 2022-2024 by Jinwen XU %% ------------------------------------ %% %% This file may be distributed and/or modified under the conditions of @@ -9,11 +9,10 @@ %% %% http://www.latex-project.org/lppl.txt %% -\NeedsTeXFormat{LaTeX2e}[2020-10-01] -\RequirePackage{l3keys2e} +\NeedsTeXFormat{LaTeX2e}[2022-06-01] \ProvidesExplPackage {multifootnote} - {2022/05/31} {} + {2024/03/24} {} {Multiple numbers for the same footnote} \msg_new:nnn { multifootnote } @@ -37,6 +36,9 @@ \keys_define:nn { multifootnote } { + , backref .bool_set:N = \l__multifootnote_backref_bool + , backref .initial:n = { false } + , left-align .bool_set:N = \l__multifootnote_left_align_bool , left-align .initial:n = { false } , left~align .bool_set:N = \l__multifootnote_left_align_bool @@ -56,9 +58,23 @@ \dim_set:Nn \l__multifootnote_left_indent_dim { #1 } } , left indent .default:n = { 1.5em } + + , manual .bool_set:N = \l__multifootnote_manual_mode_bool + , manual .initial:n = { false } + , manual-mode .bool_set:N = \l__multifootnote_manual_mode_bool + , manual~mode .bool_set:N = \l__multifootnote_manual_mode_bool + , manual mode .bool_set:N = \l__multifootnote_manual_mode_bool + , unknown .code:n = {} } -\ProcessKeysOptions { multifootnote } +\ProcessKeyOptions [ multifootnote ] + +\bool_if:NT \l__multifootnote_backref_bool + { + \RequirePackage { hyperref } + } + +\RequirePackage { refcount } \cs_new_protected:Nn \multifootnote_make_footnote_left_align:n { @@ -83,8 +99,26 @@ \multifootnote_make_footnote_left_align:n { \l__multifootnote_left_indent_dim } } +\cs_generate_variant:Nn \iow_now:Nn { ce } +\cs_generate_variant:Nn \clist_put_right:Nn { ce } + +\tl_new:N \l__multifootnote_tmp_tl +\seq_new:N \l__multifootnote_tmp_seq +\clist_new:N \l__multifootnote_tmp_clist + +% get the total page number +\hook_gput_code:nnn { enddocument } { multifootnote } + { + \label{multifootnote_last-page} + } +\int_new:N \g_multifootnote_total_page_int +\hook_gput_code:nnn { begindocument } { multifootnote } + { + \int_gset:Nn \g_multifootnote_total_page_int { \getpagerefnumber{multifootnote_last-page} } + } + % First approach -\NewDocumentCommand \multifootnotemark { O{} } +\NewDocumentCommand \multifootnotemarkmanual { O{} } { \footnotemark \group_begin: @@ -92,69 +126,265 @@ { \addtocounter { footnote } { -1 } \refstepcounter { footnote } + \label { multifootnote-mark-#1 } \@ifpackageloaded { hyperref } { \cs_gset_eq:NN \@currentHref \Hy@footnote@currentHref } {} - \label { #1 } + \label { multifootnote-#1 } } \group_end: } -\NewCommandCopy \footnotenumber \multifootnotemark +\NewCommandCopy \footnotenumbermanual \multifootnotemarkmanual -\NewDocumentCommand \multifootnotetext { O{} m } +\NewDocumentCommand \multifootnotetextmanual { O{} m } { \group_begin: - \clist_clear:N \l_tmpa_clist - \clist_clear:N \l_tmpb_clist - \tl_if_blank:nF { #1 } + \tl_if_blank:nTF { #1 } { + \footnotetext { #2 } + } + { + \clist_clear:N \l_tmpa_clist + \clist_clear:N \l_tmpb_clist \clist_map_inline:nn { #1 } { \@ifpackageloaded { hyperref } { - \clist_put_right:Nn \l_tmpa_clist - { \ref*{ ##1 } } + \bool_if:NTF \l__multifootnote_backref_bool + { + \clist_put_right:Nn \l_tmpa_clist + { \hyperref[multifootnote-mark-##1]{ \ref*{ multifootnote-##1 } } } + } + { + \clist_put_right:Nn \l_tmpa_clist + { \ref*{ multifootnote-##1 } } + } \clist_put_right:Nn \l_tmpb_clist - { \Hy@raisedlink { \hypertarget { \getrefbykeydefault{##1}{anchor}{Doc-Start} } {} } } + { \Hy@raisedlink { \hypertarget { \getrefbykeydefault{multifootnote-##1}{anchor}{Doc-Start} } {} } } } { \clist_put_right:Nn \l_tmpa_clist - { \ref { ##1 } } + { \ref { multifootnote-##1 } } } } \def \thefootnote { \clist_use:Nn \l_tmpa_clist { , \skip_horizontal:n { \l_multifootnote_space_after_comma_dim } } } + \@ifpackageloaded { hyperref } + { + \xdef \Hy@footnote@currentHref { x\Hy@footnote@currentHref } + } {} + \footnotetext { \clist_use:Nn \l_tmpb_clist {} \ignorespaces #2 } } - \@ifpackageloaded { hyperref } - { - \xdef \Hy@footnote@currentHref { x\Hy@footnote@currentHref } - } {} - \footnotetext { \clist_use:Nn \l_tmpb_clist {} \ignorespaces #2 } \group_end: } -% Second approach -\NewDocumentCommand \multifootnotetag { m } +\seq_new:N \g__multifootnote_mark_internal_seq +\cs_new:Nn \__multifootnote_process_per_page_mark:nnnN + % #1 = labels + % #2 = footnote text + % #3 = actual page number + % #4 = a macro to store the result { + \tl_gclear:N #4 + \clist_clear:N \l_tmpa_clist + \clist_map_inline:nn { #1 } + { + % only keep those labels that appear on the current page + \str_if_eq:eeT { #3 } { \getpagerefnumber{multifootnote-mark-##1} } + { + \clist_put_right:Nn \l_tmpa_clist { ##1 } + } + } + \clist_if_empty:NF \l_tmpa_clist + { + \tl_gput_right:No #4 { \exp_after:wN { \l_tmpa_clist } } + \tl_gput_right:Nn #4 { { #2 } } + } + } +\hook_gput_code:nnn { begindocument } { multifootnote/mark } + { + \int_step_inline:nn { \int_eval:n { \g_multifootnote_total_page_int } } + { + % generate the per page mark-footnotetext sequences + % \tl_show:n { g__multifootnote_mark_internal_page_ #1 _seq } + \seq_new:c { g__multifootnote_mark_internal_page_ #1 _seq } + \seq_new:c { g__multifootnote_mark_internal_page_ #1 _recorded_seq } + % keep only those labels appeared on the current page + \seq_clear:N \l__multifootnote_tmp_seq + \seq_map_inline:cn { g__multifootnote_mark_internal_seq } + { + % \tl_show:n { TEST:~##1 } + \__multifootnote_process_per_page_mark:nnnN ##1 { #1 } \l__multifootnote_tmp_tl + \tl_if_empty:NF \l__multifootnote_tmp_tl + { + \seq_put_right:No \l__multifootnote_tmp_seq { \l__multifootnote_tmp_tl } + } + } + \seq_gset_eq:cN { g__multifootnote_mark_internal_page_ #1 _seq } \l__multifootnote_tmp_seq + % \seq_show:c { g__multifootnote_mark_internal_page_ #1 _seq } + } + } + +\NewDocumentCommand \multifootnotemark { O{} } + { + % print the footnote mark \footnotemark \group_begin: - \def \thefootnote {} - \footnotetext { \vspace { -\baselineskip } } + \tl_if_blank:nF { #1 } + { + \addtocounter { footnote } { -1 } + \refstepcounter { footnote } + \label { multifootnote-mark-#1 } + \@ifpackageloaded { hyperref } + { + \cs_gset_eq:NN \@currentHref \Hy@footnote@currentHref + } {} + \label { multifootnote-#1 } + } \group_end: + % print the corresponding footnote text + \tl_if_blank:nF { #1 } + { + \tl_set:Ne \l__multifootnote_tmp_tl { \getpagerefnumber{multifootnote-mark-#1} } + % \tl_show:N \l__multifootnote_tmp_tl + % \seq_show:c { g__multifootnote_mark_internal_page_ \l__multifootnote_tmp_tl _seq } + \seq_map_inline:cn { g__multifootnote_mark_internal_page_ \l__multifootnote_tmp_tl _seq } + { + % \tl_show:n { TEST:~ { #1 } ##1 } + \seq_if_in:cnF { g__multifootnote_mark_internal_page_ \l__multifootnote_tmp_tl _recorded_seq } { ##1 } + { + % \tl_show:n { TEST:~ { #1 } ##1 } + \__multifootnote_print_footnotetext:nnnnn { #1 } ##1 + { + % record the current item + \seq_gput_right:cn { g__multifootnote_mark_internal_page_ \l__multifootnote_tmp_tl _recorded_seq } { ##1 } + % \seq_show:c { g__multifootnote_mark_internal_page_ \l__multifootnote_tmp_tl _recorded_seq } + } {} + {} {} % the two extra empty groups are added for safety + } + } + } + } +\cs_new:Nn \__multifootnote_print_footnotetext:nnnnn + % #1 = a given label + % #2 = labels + % #3 = footnote text + % #4 = code when the footnote text is indeed printed + % #5 = fallback code when the footnote text does not get printed + { + % \tl_show:n { TEST:~ { #1 } { #2 } { #3 } } + % \clist_if_in:nnTF { #2 } { #1 } { \tl_show:n { TEST:~ {#1}~is~in~{#2}. } } { \tl_show:n { TEST:~ {#1}~is~NOT~in~{#2}. } } + \clist_if_in:nnTF { #2 } { #1 } + { + \clist_clear:N \l_tmpa_clist + \clist_clear:N \l_tmpb_clist + % \clist_show:n { #2 } + \clist_map_inline:nn { #2 } + { + \@ifpackageloaded { hyperref } + { + \bool_if:NTF \l__multifootnote_backref_bool + { + \clist_put_right:Nn \l_tmpa_clist + { \hyperref[multifootnote-mark-##1]{ \ref*{ multifootnote-##1 } } } + } + { + \clist_put_right:Nn \l_tmpa_clist + { \ref*{ multifootnote-##1 } } + } + \clist_put_right:Nn \l_tmpb_clist + { \Hy@raisedlink { \hypertarget { \getrefbykeydefault{multifootnote-##1}{anchor}{Doc-Start} } {} } } + } + { + \clist_put_right:Nn \l_tmpa_clist + { \ref { multifootnote-##1 } } + } + } + % \clist_show:N \l_tmpa_clist + \group_begin: + \def \thefootnote { \clist_use:Nn \l_tmpa_clist { , \skip_horizontal:n { \l_multifootnote_space_after_comma_dim } } } + \@ifpackageloaded { hyperref } + { + \xdef \Hy@footnote@currentHref { x\Hy@footnote@currentHref } + } {} + \footnotetext { \clist_use:Nn \l_tmpb_clist {} \ignorespaces #3 } + \group_end: + #4 + } + { + #5 + } + } +\NewCommandCopy \footnotenumber \multifootnotemark + +\NewDocumentCommand \multifootnotetext { O{} m } + { + \tl_if_blank:nTF { #1 } + { + \footnotetext { #2 } + } + { + \iow_now:cn { @auxout } + { + \@multifootnote@add@to@mark@text@list { #1 } { #2 } + } + } + } +\NewDocumentCommand \@multifootnote@add@to@mark@text@list { m m } + { + \seq_gput_right:Nn \g__multifootnote_mark_internal_seq { { #1 } { #2 } } + } + +% Second approach +\int_new:N \g__multifootnote_tag_footnotemark_counter_int + +\NewDocumentCommand \multifootnotetagmanual { m } + { + \footnotemark + \@ifpackageloaded { hyperref } + { + \int_gdecr:N \g__multifootnote_tag_footnotemark_counter_int + \addtocounter { footnote } { -1 } + \refstepcounter { footnote } + \label { multifootnote-tag-mark- \int_eval:n { \g__multifootnote_tag_footnotemark_counter_int } } + \cs_gset_eq:NN \@currentHref \Hy@footnote@currentHref + \label { multifootnote-tag-footnote- \int_eval:n { \g__multifootnote_tag_footnotemark_counter_int } } + \clist_map_inline:nn { #1 } + { + % generate hypertargets for footnote marks so that they can jump correctly to the corresponding footnotes + \clist_if_exist:cF { multifootnote-tag-hypertarget- ##1 } + { \clist_new:c { multifootnote-tag-hypertarget- ##1 } } + \clist_put_right:ce { multifootnote-tag-hypertarget- ##1 } + { \exp_not:N \Hy@raisedlink { \exp_not:N \hypertarget { \exp_not:N \getrefbykeydefault{ multifootnote-tag-footnote- \int_eval:n { \g__multifootnote_tag_footnotemark_counter_int } }{anchor}{Doc-Start} } {} } } + } + } {} \clist_map_inline:nn { #1 } { - \cs_if_exist:cTF { multifootnote-tag- ##1 } + % generate list of marks in the footnote + \bool_if:NTF \l__multifootnote_backref_bool { - \tl_gput_right:cx { multifootnote-tag- ##1 } { , \skip_horizontal:n { \l_multifootnote_space_after_comma_dim } \thefootnote } + \cs_if_exist:cTF { multifootnote-tag-list- ##1 } + { + \tl_gput_right:ce { multifootnote-tag-list- ##1 } { , \skip_horizontal:n { \l_multifootnote_space_after_comma_dim } \ref { multifootnote-tag-mark- \int_eval:n { \g__multifootnote_tag_footnotemark_counter_int } } } + } + { + \cs_gset:cpx { multifootnote-tag-list- ##1 } { \ref { multifootnote-tag-mark- \int_eval:n { \g__multifootnote_tag_footnotemark_counter_int } } } + } } { - \cs_gset:cpx { multifootnote-tag- ##1 } { \thefootnote } + \cs_if_exist:cTF { multifootnote-tag-list- ##1 } + { + \tl_gput_right:ce { multifootnote-tag-list- ##1 } { , \skip_horizontal:n { \l_multifootnote_space_after_comma_dim } \thefootnote } + } + { + \cs_gset:cpx { multifootnote-tag-list- ##1 } { \thefootnote } + } } } } -\NewCommandCopy \footnotetag \multifootnotetag +\NewCommandCopy \footnotetagmanual \multifootnotetagmanual -\NewDocumentCommand \multifootnotetagtext { O{} m } +\NewDocumentCommand \multifootnotetagtextmanual { O{} m } { \group_begin: \tl_if_blank:nTF { #1 } @@ -162,13 +392,148 @@ \def \thefootnote { } } { - \def \thefootnote { \use:c { multifootnote-tag- #1 } } + \def \thefootnote { \use:c { multifootnote-tag-list- #1 } } + } + \@ifpackageloaded { hyperref } + { + \xdef \Hy@footnote@currentHref { x\Hy@footnote@currentHref } + \footnotetext { \clist_use:cn { multifootnote-tag-hypertarget- #1 } {} \ignorespaces #2 } + } + { + \footnotetext { #2 } } - \footnotetext { #2 } \group_end: } +\prop_new:N \g__multifootnote_tag_internal_prop +\NewDocumentCommand \multifootnotetag { m } + { + \footnotemark + \int_gdecr:N \g__multifootnote_tag_footnotemark_counter_int + \addtocounter { footnote } { -1 } + \refstepcounter { footnote } + \label { multifootnote-tag-mark- \int_eval:n { \g__multifootnote_tag_footnotemark_counter_int } } + % add the current label number to the clist of the given tag on the current page + \clist_map_inline:nn { #1 } + { + \iow_now:ce { @auxout } + { + \@multifootnote@add@to@tag@label@list + { ##1 } + { \int_eval:n { \g__multifootnote_tag_footnotemark_counter_int } } + { \getpagerefnumber { multifootnote-tag-mark- \int_eval:n { \g__multifootnote_tag_footnotemark_counter_int } } } + } + } + \@ifpackageloaded { hyperref } + { + \cs_gset_eq:NN \@currentHref \Hy@footnote@currentHref + \label { multifootnote-tag-footnote- \int_eval:n { \g__multifootnote_tag_footnotemark_counter_int } } + } {} + \clist_map_inline:nn { #1 } + { + \clist_if_exist:cF { g__multifootnote_tag_page_ \getpagerefnumber { multifootnote-tag-mark- \int_eval:n { \g__multifootnote_tag_footnotemark_counter_int } } _recorded_clist } + { + \clist_new:c { g__multifootnote_tag_page_ \getpagerefnumber { multifootnote-tag-mark- \int_eval:n { \g__multifootnote_tag_footnotemark_counter_int } } _recorded_clist } + } + \clist_if_in:cnF { g__multifootnote_tag_page_ \getpagerefnumber { multifootnote-tag-mark- \int_eval:n { \g__multifootnote_tag_footnotemark_counter_int } } _recorded_clist } { ##1 } + { + \clist_gput_right:cn { g__multifootnote_tag_page_ \getpagerefnumber { multifootnote-tag-mark- \int_eval:n { \g__multifootnote_tag_footnotemark_counter_int } } _recorded_clist } { ##1 } + \group_begin: + % \clist_show:c { g__multifootnote_tag_ ##1 _page_ \getpagerefnumber { multifootnote-tag-mark- \int_eval:n { \g__multifootnote_tag_footnotemark_counter_int } } _clist } + \clist_if_exist:cT { g__multifootnote_tag_ ##1 _page_ \getpagerefnumber { multifootnote-tag-mark- \int_eval:n { \g__multifootnote_tag_footnotemark_counter_int } } _clist } + { % skip the following code on the first run + \clist_clear:N \l__multifootnote_tmp_clist + \clist_map_inline:cn { g__multifootnote_tag_ ##1 _page_ \getpagerefnumber { multifootnote-tag-mark- \int_eval:n { \g__multifootnote_tag_footnotemark_counter_int } } _clist } + { + % generate list of marks in the footnote + \clist_put_right:Nn \l__multifootnote_tmp_clist + { + % \tl_show:n { ####1 } + \bool_if:NTF \l__multifootnote_backref_bool + { + \ref { multifootnote-tag-mark- ####1 } + } + { + \@ifpackageloaded { hyperref } + { + \ref*{ multifootnote-tag-mark- ####1 } + } + { + \ref { multifootnote-tag-mark- ####1 } + } + } + } + \@ifpackageloaded { hyperref } + { + % generate hypertargets for footnote marks so that they can jump correctly to the corresponding footnotes + \clist_if_exist:cF { multifootnote-tag-hypertarget- ##1 -page- \getpagerefnumber { multifootnote-tag-mark- \int_eval:n { \g__multifootnote_tag_footnotemark_counter_int } } } + { \clist_new:c { multifootnote-tag-hypertarget- ##1 -page- \getpagerefnumber { multifootnote-tag-mark- \int_eval:n { \g__multifootnote_tag_footnotemark_counter_int } } } } + \clist_put_right:ce { multifootnote-tag-hypertarget- ##1 -page- \getpagerefnumber { multifootnote-tag-mark- \int_eval:n { \g__multifootnote_tag_footnotemark_counter_int } } } + { \exp_not:N \Hy@raisedlink { \exp_not:N \hypertarget { \exp_not:N \getrefbykeydefault{ multifootnote-tag-footnote- ####1 }{anchor}{Doc-Start} } {} } } + } {} + } + % \clist_show:N \l__multifootnote_tmp_clist + \def \thefootnote { \clist_use:Nn \l__multifootnote_tmp_clist { , \skip_horizontal:n { \l_multifootnote_space_after_comma_dim } } } + \@ifpackageloaded { hyperref } + { + \xdef \Hy@footnote@currentHref { x\Hy@footnote@currentHref } + \footnotetext + { + \clist_use:cn { multifootnote-tag-hypertarget- ##1 -page- \getpagerefnumber { multifootnote-tag-mark- \int_eval:n { \g__multifootnote_tag_footnotemark_counter_int } } } {} \ignorespaces + \prop_item:Nn \g__multifootnote_tag_internal_prop { ##1 } + } + } + { + \footnotetext { \prop_item:Nn \g__multifootnote_tag_internal_prop { ##1 } } + } + } + \group_end: + } + } + } +\NewCommandCopy \footnotetag \multifootnotetag +\NewDocumentCommand \@multifootnote@add@to@tag@label@list { m m m } + % #1 = tag + % #2 = label number + % #3 = page number + { + \clist_if_exist:cF { g__multifootnote_tag_ #1 _page_ #3 _clist } + { + \clist_new:c { g__multifootnote_tag_ #1 _page_ #3 _clist } + } + \clist_gput_right:cn { g__multifootnote_tag_ #1 _page_ #3 _clist } { #2 } + % \clist_show:c { g__multifootnote_tag_ #1 _page_ #3 _clist } + } + +\NewDocumentCommand \multifootnotetagtext { O{} m } + { + \tl_if_blank:nTF { #1 } + { + \footnotetext { #2 } + } + { + \iow_now:cn { @auxout } + { + \@multifootnote@add@to@tag@text@list { #1 } { #2 } + } + } + } +\NewDocumentCommand \@multifootnote@add@to@tag@text@list { m m } + { + \prop_gput:Nnn \g__multifootnote_tag_internal_prop { #1 } { #2 } + } + % The combined interface for producing footnote text +\NewDocumentCommand \multifootnotemanual { O{} m } + { + \str_if_in:nnTF { #1 } { , } + { + \multifootnotetextmanual [ #1 ] { #2 } + } + { + \multifootnotetagtextmanual [ #1 ] { #2 } + } + } \NewDocumentCommand \multifootnote { O{} m } { \str_if_in:nnTF { #1 } { , } @@ -180,6 +545,17 @@ } } +\bool_if:NT \l__multifootnote_manual_mode_bool + { + \RenewCommandCopy \multifootnotemark \multifootnotemarkmanual + \RenewCommandCopy \multifootnotetext \multifootnotetextmanual + \RenewCommandCopy \multifootnotetag \multifootnotetagmanual + \RenewCommandCopy \multifootnotetagtext \multifootnotetagtextmanual + \RenewCommandCopy \multifootnote \multifootnotemanual + \RenewCommandCopy \footnotenumber \footnotenumbermanual + \RenewCommandCopy \footnotetag \footnotetagmanual + } + \endinput %% %% End of file `multifootnote.sty'. |