diff options
author | Karl Berry <karl@freefriends.org> | 2021-01-23 22:18:39 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2021-01-23 22:18:39 +0000 |
commit | 5c1a691dfa92a49c802beeeb7f1b193698b51216 (patch) | |
tree | 9acdd0d98593a199eaad24ff8338309ce3e9af95 /Master/texmf-dist/tex | |
parent | 3fc4de03f2da103a96f5d0cc757300f8c7e311f1 (diff) |
fnpct (23jan21)
git-svn-id: svn://tug.org/texlive/trunk@57505 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex')
-rw-r--r-- | Master/texmf-dist/tex/latex/fnpct/fnpct.sty | 1883 |
1 files changed, 1033 insertions, 850 deletions
diff --git a/Master/texmf-dist/tex/latex/fnpct/fnpct.sty b/Master/texmf-dist/tex/latex/fnpct/fnpct.sty index bdd63448cd2..4485a3badab 100644 --- a/Master/texmf-dist/tex/latex/fnpct/fnpct.sty +++ b/Master/texmf-dist/tex/latex/fnpct/fnpct.sty @@ -5,35 +5,31 @@ % % -------------------------------------------------------------------------- % Clemens Niederberger -% Web: https://bitbucket.org/cgnieder/fnpct/ +% Web: https://github.com/cgnieder/fnpct/ % E-Mail: contact@mychemistry.eu % -------------------------------------------------------------------------- -% Copyright 2012--2019 Clemens Niederberger +% Copyright 2012--2021 Clemens Niederberger % % This work may be distributed and/or modified under the -% conditions of the LaTeX Project Public License, either version 1.3 +% conditions of the LaTeX Project Public License, either version 1.3c % of this license or (at your option) any later version. % The latest version of this license is in % http://www.latex-project.org/lppl.txt -% and version 1.3 or later is part of all distributions of LaTeX -% version 2005/12/01 or later. +% and version 1.3c or later is part of all distributions of LaTeX +% version 2008/05/04 or later. % % This work has the LPPL maintenance status `maintained'. % % The Current Maintainer of this work is Clemens Niederberger. % -------------------------------------------------------------------------- -% If you have any ideas, questions, suggestions or bugs to report, please -% feel free to contact me. -% -------------------------------------------------------------------------- -% the package is inspired by the following question on TeX.SE: -% http://tex.stackexchange.com/q/56094/5049 -% -------------------------------------------------------------------------- -\RequirePackage {xparse,l3keys2e,scrlfile} +\RequirePackage {l3keys2e} \ExplSyntaxOn -\tl_const:Nn \c_fnpct_date_tl {2019/10/05} -\tl_const:Nn \c_fnpct_version_major_number_tl {0} -\tl_const:Nn \c_fnpct_version_minor_number_tl {5} +\DeclareHookRule {begindocument} {fnpct} {after} {hyperref} + +\tl_const:Nn \c_fnpct_date_tl {2021/01/21} +\tl_const:Nn \c_fnpct_version_major_number_tl {1} +\tl_const:Nn \c_fnpct_version_minor_number_tl {0} \tl_const:Nn \c_fnpct_version_subrelease_tl {} \tl_const:Nx \c_fnpct_version_number_tl { @@ -54,107 +50,129 @@ {\c_fnpct_info_tl} % -------------------------------------------------------------------------- -% this is plain's \nobreak: -\cs_new:Npn \fnpct_no_break: { \tex_penalty:D 10000 \scan_stop: } - -% -------------------------------------------------------------------------- -% variables: +% scratch variables and variants of kernel functions: \tl_new:N \l__fnpct_tmpa_tl -\tl_new:N \l__fnpct_tmpb_tl -\dim_new:N \l__fnpct_tmpa_dim -\dim_new:N \l__fnpct_tmpb_dim +\seq_new:N \l__fnpct_tmpa_seq -\int_new:N \l__fnpct_tmpa_int +\cs_generate_variant:Nn \tl_remove_all:Nn {NV} +\cs_generate_variant:Nn \prop_item:Nn {NV} +\cs_generate_variant:Nn \prop_get:NnN {NV} +\cs_generate_variant:Nn \prop_put:Nnn {Nx,Nnx,Nxx} +\cs_generate_variant:Nn \seq_put_right:Nn {Nx} +\cs_generate_variant:Nn \seq_set_split:Nnn {NV} +\cs_generate_variant:Nn \regex_replace_all:nnN {nx} +\cs_generate_variant:Nn \str_remove_once:Nn {NV} +\cs_generate_variant:Nn \msg_warning:nnn {nnV} +\cs_generate_variant:Nn \msg_warning:nnnn {nnV} +\cs_generate_variant:Nn \msg_error:nnn {nnV} -\seq_new:N \l__fnpct_tmpa_seq -\seq_new:N \l__fnpct_tmpb_seq - -\dim_new:N \l__fnpct_after_comma_dim -\dim_set:Nn \l__fnpct_after_comma_dim {-.06em} -\dim_new:N \l__fnpct_after_dot_dim -\dim_set:Nn \l__fnpct_after_dot_dim {-.06em} -\dim_new:N \l__fnpct_before_comma_dim -\dim_set:Nn \l__fnpct_before_comma_dim {-.16em} -\dim_new:N \l__fnpct_before_dot_dim -\dim_set:Nn \l__fnpct_before_dot_dim {-.16em} -\dim_new:N \l__fnpct_before_footnote_dim -\dim_set:Nn \l__fnpct_before_footnote_dim {.06em} -\dim_new:N \l__fnpct_normal_mark_width_dim -\dim_set:Nn \l__fnpct_normal_mark_width_dim {1em} -\dim_new:N \l__fnpct_normal_indent_dim -\dim_set:Nn \l__fnpct_normal_indent_dim {1.5em} -\dim_new:N \l__fnpct_normal_parindent_dim -\dim_set:Nn \l__fnpct_normal_parindent_dim {1em} -\dim_new:N \l__fnpct_french_before_footnote_space_dim -\dim_set:Nn \l__fnpct_french_before_footnote_space_dim {.16667em} - -\int_new:N \l__fnpct_multiple_notes_int - -\tl_new:N \l__fnpct_multiple_footnotes_delimiter_tl -\tl_set:Nn \l__fnpct_multiple_footnotes_delimiter_tl {;} -\tl_new:N \l__fnpct_multiple_footnote_separator_tl -\tl_new:N \l__fnpct_last_punct_mark_tl -\tl_new:N \l__fnpct_punctuation_marks_tl -\tl_set:Nn \l__fnpct_punctuation_marks_tl {.,} -\tl_new:N \l__fnpct_multiple_true_tl -\tl_new:N \l__fnpct_multiple_false_tl - -\bool_new:N \l__fnpct_strict_bool -\bool_new:N \l__fnpct_punct_after_bool +\prg_generate_conditional_variant:Nnn \tl_if_eq:nn {v,V} {T,F,TF} + +% -------------------------------------------------------------------------- +% variables +\bool_new:N \l_fnpct_trailing_action_bool +\bool_new:N \l__fnpct_trailing_tokens_bool \bool_new:N \l__fnpct_dont_mess_around_bool -\bool_new:N \l__fnpct_multiple_default_bool -\bool_new:N \l__fnpct_multiple_footnotes_bool -\bool_new:N \l__fnpct_reverse_switch_bool -\bool_new:N \l__fnpct_normal_marks_bool -\bool_new:N \l__fnpct_hyperref_bool -\bool_new:N \g__fnpct_after_punctuation_bool -\bool_new:N \g__fnpct_only_text_bool -\bool_new:N \l__fnpct_makepagenote_bool - -\seq_new:N \l__fnpct_multiple_footnotes_seq +\bool_new:N \l__fnpct_ranges_bool +\bool_new:N \l__fnpct_inside_range_bool +\bool_new:N \l__fnpct_collection_bool +\bool_new:N \l__fnpct_switched_bool +\bool_new:N \l__fnpct_end_collection_bool +\bool_new:N \l__fnpct_automatic_adaption_bool +\bool_new:N \l__fnpct_reverse_bool +\bool_new:N \l__fnpct_keep_ranges_bool +\bool_new:N \g__fnpct_multiple_bool +\bool_new:N \g__fnpct_text_bool +\bool_new:N \l__fnpct_debug_bool + +\tl_new:N \l_fnpct_action_tl +\tl_new:N \l_fnpct_last_action_tl +\tl_new:N \l_fnpct_trailing_token_tl +\tl_new:N \l__fnpct_trailing_tokens_tl +\tl_new:N \l__fnpct_range_tl +\tl_new:N \l__fnpct_separate_tl +\tl_new:N \l__fnpct_multiple_footnotes_delimiter_tl +\tl_set:Nn \l__fnpct_multiple_footnotes_delimiter_tl {;} +\tl_new:N \g__fnpct_this_note_tl + +\prop_new:N \l__fnpct_trailing_tokens_prop +\prop_new:N \l__fnpct_trailing_actions_prop +\prop_new:N \l__fnpct_trailing_classes_prop +\prop_new:N \g__fnpct_actions_prop +\prop_new:N \g__fnpct_action_classes_prop + +\seq_new:N \l__fnpct_trailing_tokens_seq +\seq_new:N \l__fnpct_classes_seq +\seq_new:N \g__fnpct_actions_seq \seq_new:N \l__fnpct_footnote_class_seq +\seq_new:N \l__fnpct_collection_seq +\seq_new:N \g__fnpct_inner_seq +\seq_new:N \l__fnpct_adapted_commands_seq -\prop_new:N \l__fnpct_punctuation_marks_after_prop -\prop_new:N \l__fnpct_punctuation_marks_before_prop -\prop_new:N \l__fnpct_sepfootnote_foot_classes_prop -\prop_new:N \l__fnpct_sepfootnote_end_classes_prop -\prop_new:N \l__fnpct_sepfootnote_symbol_classes_prop -\prop_new:N \g__fnpct_adapted_notes_prop -\prop_new:N \g__fnpct_inner_footnote_prop -\prop_new:N \g__fnpct_inner_footnote_hyperref_prop -\prop_new:N \l__fnpct_footnote_fixfoot_prop +\int_new:N \l__fnpct_collection_int -% -------------------------------------------------------------------------- -% variants: -\cs_generate_variant:Nn \str_remove_once:Nn {NV} -\cs_generate_variant:Nn \tl_remove_all:Nn {NV} -\cs_generate_variant:Nn \tl_put_right:Nn {NV} -\cs_generate_variant:Nn \seq_set_split:Nnn {NnV,NV} -\cs_generate_variant:Nn \prop_gput:Nnn {Nxn,Nxo} -\cs_generate_variant:Nn \prop_put:Nnn {Nnx} -\cs_generate_variant:Nn \prop_if_in:NnTF {Nx} +\dim_new:N \l__fnpct_before_footnote_dim % -------------------------------------------------------------------------- % messages: -\cs_new_protected:Npn \fnpct_dont_mess_around: +\msg_new:nnn {fnpct} {load-time-option} + { + `#1'~ is~ a~ load-time~ option! \\ + You~ cannot~ set~ it~ with~ \token_to_str:N \setfnpct ! \\ + You~ need~ to~ use~ \token_to_str:N \usepackage [#1] {fnpct} . + } + +\msg_new:nnn {fnpct} {unknown-option} + { + Unknown~ option~ `#1'! \\ + I~ don't~ know~ the~ option~ `#1'.~ Please~ make~ sure~ there~ is~ no~ + typo.~ Check~ the~ manual~ for~ help. + } + +\msg_new:nnn {fnpct} {dont-mess-around} + { + All~ right,~ not~ messing~ around.~ :( \\ + I'd~ really~ love~ to,~ though! \\ + https://www.youtube.com/results?search_query=mess+around+ray+charles + } + +\msg_new:nnn {fnpct} {class-not-defined} + { The~ action~ class~ `#1'~ is~ not~ defined~ \msg_line_context: } + +\msg_new:nnn {fnpct} {command-not-adapted} + { The~ command~ `#1'~ doesn't~ seem~ to~ be~ adapted,~ yet,~ \msg_line_context: } + +\msg_new:nnn {fnpct} {cannot-adapt} + { + Due~ to~ the~ implementation~ of~ the~ `#1'~ package~ I~ am~ not~ yet~ + able~ to~ adapt~ its~ commands. + } + +\msg_new:nnn {fnpct} {cannot-adapt-with-ranges} { - \iow_log:n { ................................................. } - \iow_log:n { . ~ fnpct~info: } - \iow_log:n { . } - \iow_log:n { . ~ All~right,~not~messing~around.~:( } - \iow_log:n { . ~ But~I'd~really~love~to. } - \iow_log:n { . ~ (https://www.youtube.com/results?search_query=mess+around+ray+charles) } - \iow_log:n { ................................................. } + Due~ to~ the~ implementation~ of~ the~ `#1'~ package~ I~ am~ not~ yet~ + able~ to~ adapt~ its~ commands~ while~ also~ using~ the~ option~ `ranges~ + =~ true'.~ #2 } -\msg_new:nnn {fnpct} {already-adapted} +\msg_new:nnn {fnpct} {ranges-hyperref} { - The~ command~ \token_to_str:N #1 \c_space_tl has~ already~ been~ - adapted. \\ - I~ will~ do~ nothing~ instead. + Using~ the~ option~ `ranges~ =~ true'~ together~ with~ package~ + `hyperref'~ does~ not~ work~ well.~ Disabling~ ranges.~ If~ you~ insist~ + then~ set~ `keep-ranges~ =~ true'. } +\msg_new:nnn {fnpct} {keep-ranges-hyperref} + { + Using~ the~ option~ `ranges~ =~ true'~ together~ with~ package~ + `hyperref'~ does~ not~ work~ well.~ Keeping~ them~ anyway.~ But~ don't~ + say~ you~ haven't~ been~ warned. + } + +\msg_new:nnn {fnpct} {ranges-disabled} + { Using~ ranges~ is~ disabled~ \msg_line_context: . } + \msg_new:nnn {fnpct} {pagenote} { If~ you~ use~ the~ `pagenote'~ package~ with~ `fnpct'~ please~ make~ sure~ @@ -162,20 +180,64 @@ `fnpct'! } -\msg_new:nnn {fnpct} {deprecated} +\msg_new:nnn {fnpct} {option-deprecated} { - You've~ tried~ setting~ #1~ `#2'~ \msg_line_context: .~ However,~ - #1~ `#2'~ is~ deprecated.~ - \tl_if_blank:nF {#3} {Please~ use~ #1~ `#3'~ instead.~} - Refer~ to~ the~ manual~ for~ details. + The~ option~ `#1'~ is~ deprecated + \tl_if_blank:nF {#2} + { .~ Please~ use~ option~ `#2'~ instead } + \c_space_tl \msg_line_context: . } -\cs_new_protected:Npn \fnpct_message:nx #1#2 +\msg_new:nnn {fnpct} {command-removed} + { The~ command~ #1~ has~ been~ removed~ from~ fnpct. } + +% -------------------------------------------------------------------------- +\cs_new_protected:Npn \__fnpct_loadtime_error:n #1 + { \msg_error:nnV {fnpct} {#1} \l_keys_key_str } + +\cs_new_protected:Npn \__fnpct_loadtime_warning:n #1 + { \msg_warning:nnV {fnpct} {#1} \l_keys_key_str } + +\keys_define:nn {fnpct/package} { - \bool_if:NTF \l__fnpct_strict_bool - { \msg_error:nnx {fnpct} {#1} } - { \msg_warning:nnx {fnpct} {#1} } - {#2} + multiple .bool_gset:N = \g__fnpct_multiple_bool , + multiple .initial:n = false , + debug .bool_gset:N = \g__fnpct_debug_bool , + debug .initial:n = false , + dont-mess-around .choice: , + dont-mess-around / true .code:n = + \bool_set_true:N \l__fnpct_dont_mess_around_bool + \msg_info:nn {fnpct} {dont-mess-around} , + dont-mess-around / false .code:n = + \bool_set_false:N \l__fnpct_dont_mess_around_bool , + dont-mess-around .default:n = true , + dont-mess-around .initial:n = false , + unknown .code:n = + \__fnpct_loadtime_warning:n {unknown-option} + } + +\ProcessKeysPackageOptions {fnpct/package} + +\keys_define:nn {fnpct/package} + { + multiple .code:n = \__fnpct_loadtime_error:n {load-time-option} , + debug .code:n = \__fnpct_loadtime_error:n {load-time-option} , + dont-mess-around .code:n = \__fnpct_loadtime_error:n {load-time-option} + } + +% -------------------------------------------------------------------------- +\prg_new_conditional:Npnn \fnpct_if_multiple: {T,F,TF} + { + \bool_if:NTF \g__fnpct_multiple_bool + { \prg_return_true: } + { \prg_return_false: } + } + +\prg_new_conditional:Npnn \fnpct_if_debug: {T,F,TF} + { + \bool_if:NTF \g__fnpct_debug_bool + { \prg_return_true: } + { \prg_return_false: } } % -------------------------------------------------------------------------- @@ -186,979 +248,1098 @@ { \prg_return_false: } } -% -------------------------------------------------------------------------- -% multiple footnote input and output variables: -% check for KOMA-Script's \multfootsep: -\cs_if_exist:NTF \KOMAClassName - { \tl_set:Nn \l__fnpct_multiple_footnote_separator_tl { \multfootsep } } - { \tl_set:Nn \l__fnpct_multiple_footnote_separator_tl {,} } +\prg_new_conditional:Npnn \fnpct_if_class_loaded:n #1 {p,T,F,TF} + { + \@ifclassloaded {#1} + { \prg_return_true: } + { \prg_return_false: } + } % -------------------------------------------------------------------------- -% #1: before/after -% #2: punctuation mark -% #3: dimension -\cs_new_protected:Npn \fnpct_set_punctuation_dim:nnn #1#2#3 +% #1: cs +\prg_new_conditional:Npnn \fnpct_if_adapted:N #1 {T,F,TF} { - \prop_put:cnx { l__fnpct_punctuation_marks_#1_prop } - {#2} - { \dim_eval:n {#3} } + \seq_if_in:NnTF \l__fnpct_adapted_commands_seq {#1} + { \prg_return_true: } + { \prg_return_false: } } -\cs_generate_variant:Nn \fnpct_set_punctuation_dim:nnn {nV} -\fnpct_set_punctuation_dim:nnn {after} {.} { \l__fnpct_after_dot_dim } -\fnpct_set_punctuation_dim:nnn {after} {,} { \l__fnpct_after_comma_dim } -\fnpct_set_punctuation_dim:nnn {before} {.} { \l__fnpct_before_dot_dim } -\fnpct_set_punctuation_dim:nnn {before} {,} { \l__fnpct_before_comma_dim } +\prg_generate_conditional_variant:Nnn \fnpct_if_adapted:N {c} {T,F,TF} -\cs_new_protected:Npn \fnpct_rm_punctuation:n #1 +% -------------------------------------------------------------------------- +\cs_new_protected:Npn \fnpct_nobreak: { \tex_penalty:D 10000 \scan_stop: } +\cs_new_protected:Npn \fnpct_skip_nobreak:N #1 { - \tl_remove_all:Nn \l__fnpct_punctuation_marks_tl {#1} - \prop_del:Nn \l__fnpct_punctuation_marks_after_prop {#1} - \prop_del:Nn \l__fnpct_punctuation_marks_before_prop {#1} + \fnpct_nobreak: + \skip_horizontal:N #1 + \fnpct_nobreak: } +\cs_generate_variant:Nn \fnpct_skip_nobreak:N {c} -\cs_new_protected:Npn \fnpct_add_punctuation:n #1 - { \__fnpct_add_punctuation:w #1 [ \q_no_value ] \q_no_value \q_stop } -\cs_generate_variant:Nn \fnpct_add_punctuation:n {V} +% -------------------------------------------------------------------------- +% checking for trailing tokens - reuse an idea from acro +% #1: name +\cs_new_protected:Npn \fnpct_new_class:n #1 + { + \seq_put_right:Nn \l__fnpct_classes_seq {#1} + \seq_new:c {g__fnpct_class_#1_seq} + } -\cs_new_protected:Npn \__fnpct_add_punctuation:w #1[#2]#3 \q_stop +\prg_new_conditional:Npnn \fnpct_class_if_exist:n #1 {p,T,F,TF} { - \quark_if_no_value:nTF {#2} - { - % there is no option at all - \tl_map_inline:nn {#1} - { - \tl_put_right:Nn \l__fnpct_punctuation_marks_tl {##1} - \fnpct_set_punctuation_dim:nnn {after} {##1} {0pt} - \fnpct_set_punctuation_dim:nnn {before} {##1} {0pt} - \tl_set:No \l__fnpct_last_punct_mark_tl {##1} - } - } + \seq_if_in:NnTF \l__fnpct_classes_seq {#1} + { \prg_return_true: } + { \prg_return_false: } + } + +% #1: name +% #2: code +\cs_new_protected:Npn \fnpct_do_action:nnw #1#2 \fnpct_end: + { + \prop_if_in:NnTF \g__fnpct_actions_prop {#1} + { \fnpct_end: \prop_item:Nn \g__fnpct_actions_prop {#1} } + { \fnpct_end: \use:n } + {#2} + } +\cs_generate_variant:Nn \fnpct_do_action:nnw {V} + +% #1: name +% #2: class +% #3: default before dim +% #4: default after dim +% #5: code requiring two n-type arguments (code and token) +\cs_new_protected:Npn \fnpct_new_action:nnnnn #1#2#3#4#5 + { + \fnpct_class_if_exist:nTF {#2} { - \tl_if_blank:nTF {#1} - { - % #2 is a second option (= before space) - \fnpct_set_punctuation_dim:nVn {before} - \l__fnpct_last_punct_mark_tl - {#2} - } + \seq_if_in:NnTF \g__fnpct_actions_seq {#1} { - % #2 is a first option (= after space), #1 might be more than one token: - \tl_if_single_token:nTF {#1} + \keys_set:nn {fnpct} { - \tl_put_right:Nn \l__fnpct_punctuation_marks_tl {#1} - \fnpct_set_punctuation_dim:nnn {after} {#1} {#2} - \fnpct_set_punctuation_dim:nnn {before} {#1} {0pt} - \tl_set:No \l__fnpct_last_punct_mark_tl {#1} - } - { - \int_zero:N \l__fnpct_tmpa_int - \tl_map_inline:nn {#1} - { - \tl_put_right:Nn \l__fnpct_punctuation_marks_tl {##1} - \int_compare:nTF { \l__fnpct_tmpa_int < ( \tl_count:n {#1} - 1 ) } - { - \fnpct_set_punctuation_dim:nnn {after} {##1} {0pt} - \fnpct_set_punctuation_dim:nnn {before} {##1} {0pt} - } - { - \fnpct_set_punctuation_dim:nnn {after} {##1} {#2} - \fnpct_set_punctuation_dim:nnn {before} {##1} {0pt} - } - \tl_set:No \l__fnpct_last_punct_mark_tl {##1} - \int_incr:N \l__fnpct_tmpa_int - } + before-#1-space = #3 , + after-#1-space = #4 } } - } - % is there more? - \tl_if_eq:nnF {#3} { [\q_no_value]\q_no_value } - { - \quark_if_no_value:nF {#3} { - \tl_set:Nn \l__fnpct_tmpa_tl {#3} - \tl_remove_all:Nn \l__fnpct_tmpa_tl { [\q_no_value]\q_no_value } - \fnpct_add_punctuation:V \l__fnpct_tmpa_tl + \seq_gput_right:Nn \g__fnpct_actions_seq {#1} + \prop_gput:Nnn \g__fnpct_action_classes_prop {#1} {#2} + \prop_gput:Nnn \g__fnpct_actions_prop {#1} {#5} + \seq_gput_right:cn {g__fnpct_class_#2_seq} {#1} + \dim_new:c {l__fnpct_before_#1_dim} + \dim_new:c {l__fnpct_after_#1_dim} + \keys_define:nn {fnpct} + { + before-#1-space .dim_set:c = {l__fnpct_before_#1_dim} , + before-#1-space .initial:n = #3 , + after-#1-space .dim_set:c = {l__fnpct_after_#1_dim} , + after-#1-space .initial:n = #4 + } } } + { \msg_error:nnn {fnpct} {class-not-defined} {#2} } } -% -------------------------------------------------------------------------- -% options: -\keys_define:nn {fnpct} +\prg_new_conditional:Npnn \fnpct_action_if_exist:n #1 {p,T,F,TF} { - bigfoot-default-top .code:n = - \msg_warning:nnnn {fnpct} {deprecated} {option} {bigfoot-default-top} , - strict .bool_set:N = \l__fnpct_strict_bool , - after-comma-space .code:n = - \fnpct_set_punctuation_dim:nnn {after} {,} {#1} , - after-dot-space .code:n = - \fnpct_set_punctuation_dim:nnn {after} {.} {#1} , - before-comma-space .code:n = - \fnpct_set_punctuation_dim:nnn {before} {,} {#1} , - before-dot-space .code:n = - \fnpct_set_punctuation_dim:nnn {before} {.} {#1} , - after-punct-space .code:n = - \prop_map_inline:Nn \l__fnpct_punctuation_marks_after_prop - { \fnpct_set_punctuation_dim:nnn {after} {##1} {#1} } , - before-punct-space .code:n = - \prop_map_inline:Nn \l__fnpct_punctuation_marks_before_prop - { \fnpct_set_punctuation_dim:nnn {before} {##1} {#1} } , - before-footnote-space .dim_set:N = \l__fnpct_before_footnote_dim , - french-before-footnote-space .dim_set:N = - \l__fnpct_french_before_footnote_space_dim , - punct-after .bool_set:N = \l__fnpct_punct_after_bool , - dont-mess-around .code:n = - \prop_map_inline:Nn \l__fnpct_punctuation_marks_after_prop - { \fnpct_set_punctuation_dim:nnn {after} {##1} {0pt} } - \prop_map_inline:Nn \l__fnpct_punctuation_marks_before_prop - { \fnpct_set_punctuation_dim:nnn {before} {##1} {0pt} } - \dim_zero:N \l__fnpct_before_footnote_dim - \bool_set_true:N \l__fnpct_punct_after_bool - \bool_set_true:N \l__fnpct_dont_mess_around_bool - \fnpct_dont_mess_around: , - mult-fn-delim .tl_set:N = \l__fnpct_multiple_footnotes_delimiter_tl , - mult-fn-sep .tl_set:N = \l__fnpct_multiple_footnote_separator_tl , - multiple .bool_set:N = \l__fnpct_multiple_default_bool , - normal-marks .bool_set:N = \l__fnpct_normal_marks_bool , - normal-mark-width .dim_set:N = \l__fnpct_normal_mark_width_dim , - normal-indent .dim_set:N = \l__fnpct_normal_indent_dim , - normal-parindent .dim_set:N = \l__fnpct_normal_parindent_dim , - verb-format .tl_set:N = \l__fnpct_verbatim_format_tl , - add-punct-marks .code:n = \fnpct_add_punctuation:n {#1} , - remove-punct-marks .code:n = - \tl_map_function:nN {#1} \fnpct_rm_punctuation:n - } - -\ProcessKeysOptions {fnpct} + \seq_if_in:NnTF \g__fnpct_actions_seq {#1} + { \prg_return_true: } + { \prg_return_false: } + } -% -------------------------------------------------------------------------- -% MAIN INTERNAL FOOTNOTE FUNCTION: -% write the notes: -\cs_new:Npn \__fnpct_no_value_or_quark_no_value:nTF #1#2#3 +% register a new token but don't activate its action: +% #1: token +% #2: action +\cs_new_protected:Npn \fnpct_new_trailing_token:Nn #1#2 { - \IfNoValueTF {#1} {#2} - { \quark_if_no_value:nTF {#1} {#2} {#3} } + \prop_put:Nnn \l__fnpct_trailing_tokens_prop {#1} {#1} + \prop_put:Nnn \l__fnpct_trailing_actions_prop {#1} {#2} + \prop_put:Nnx \l__fnpct_trailing_classes_prop {#1} + { \prop_item:Nn \g__fnpct_action_classes_prop {#2} } + \seq_put_right:Nn \l__fnpct_trailing_tokens_seq {#1} } -\cs_new:Npn \fnpct_write_note:Nnnn #1#2#3#4 +% #1: class +% #2: code where `#1' refers to the action name +\cs_new:Npn \fnpct_foreach_action:nn #1#2 { - \__fnpct_no_value_or_quark_no_value:nTF {#2} - { #1 {#4} } - { - \__fnpct_no_value_or_quark_no_value:nTF {#3} - { #1 [#2] {#4} } - { #1 [#2] [#3] {#4} } - } + \fnpct_class_if_exist:nT {#1} + { \seq_map_inline:cn {g__fnpct_class_#1_seq} {#2} } } -% check for punctuation: -\cs_new_protected:Npn \fnpct_check_punctuation:TF #1#2 - { \__fnpct_check_punctuation:nTF {0} {#1} {#2} } +\cs_new_eq:NN \fnpct_action_break: \seq_map_break: -\cs_new_protected:Npn \__fnpct_check_punctuation:nTF #1#2#3 +% #1: token +\cs_new_protected:Npn \fnpct_remove_trailing_token:N #1 { - \__fnpct_get_head:NN - \l__fnpct_current_punct_mark_tl - \l__fnpct_punctuation_marks_tl - \exp_args:NV \peek_meaning_remove:NTF \l__fnpct_current_punct_mark_tl - {#2} - { - \__fnpct_check_punctuation_aux:nnn {#1} - { \__fnpct_check_punctuation:VTF \l__fnpct_tmpa_int {#2} {#3} } - {#3} - } + \seq_remove_all:Nn \l__fnpct_trailing_tokens_seq {#1} + \prop_remove:Nn \l__fnpct_trailing_tokens_prop {#1} + \prop_remove:Nn \l__fnpct_trailing_actions_prop {#1} + \prop_remove:Nn \l__fnpct_trailing_classes_prop {#1} } -\cs_new_protected:Npn \__fnpct_check_punctuation_aux:nnn #1#2#3 +\cs_new_protected:Npn \fnpct_for_all_trailing_tokens_do:n #1 + { \seq_map_inline:Nn \l__fnpct_trailing_tokens_seq {#1} } + +% activate a token: +\cs_new_protected:Npn \fnpct_activate_trailing_token:n #1 { - \int_set:Nn \l__fnpct_tmpa_int {#1} - \int_incr:N \l__fnpct_tmpa_int - \tl_set:Nx \l__fnpct_tmpb_tl { \int_to_arabic:n { \l__fnpct_tmpa_int } } - \tl_remove_all:NV \l__fnpct_punctuation_marks_tl - \l__fnpct_current_punct_mark_tl - \tl_put_right:NV \l__fnpct_punctuation_marks_tl - \l__fnpct_current_punct_mark_tl - \int_compare:nTF { \l__fnpct_tmpa_int < \tl_count:V \l__fnpct_punctuation_marks_tl } - {#2} - {#3} + \prop_get:NnN \l__fnpct_trailing_tokens_prop {#1} \l__fnpct_tmpa_tl + \tl_put_right:NV \l__fnpct_trailing_tokens_tl \l__fnpct_tmpa_tl } -\cs_generate_variant:Nn \__fnpct_check_punctuation:nTF {V} - -\cs_new_protected:Npn \__fnpct_get_head:NN #1#2 - { \tl_set:Nx #1 { \tl_head:V #2 } } -% check for multiple notes: -\cs_new_protected:Npn \fnpct_check_multiple:TF #1#2 +% deactivate a token: +\cs_new_protected:Npn \fnpct_deactivate_trailing_token:n #1 { - \tl_set:Nn \l__fnpct_multiple_true_tl {#1} - \tl_set:Nn \l__fnpct_multiple_false_tl {#2} - \bool_gset_false:N \g__fnpct_after_punctuation_bool - \peek_after:Nw \__fnpct_check_multiple: + \prop_get:NnN \l__fnpct_trailing_tokens_prop {#1} \l__fnpct_tmpa_tl + \tl_remove_all:NV \l__fnpct_trailing_tokens_tl \l__fnpct_tmpa_tl } -\cs_new_protected:Npn \__fnpct_check_multiple: +% #1: tokenlist +\prg_new_protected_conditional:Npnn \fnpct_if_trailing_tokens:n #1 {T,F,TF} { - \prop_map_inline:Nn \g__fnpct_adapted_notes_prop + \bool_set_false:N \l__fnpct_trailing_tokens_bool + \tl_map_inline:nn {#1} { - \tl_set_rescan:Nnn \l__fnpct_tmpb_tl {} {##1} - \exp_args:NV - \token_if_eq_meaning:NNTF \l__fnpct_tmpb_tl \l_peek_token + \bool_if:cT {l__fnpct_trailing_##1_bool} { - \bool_set_true:N \l__fnpct_multiple_footnotes_bool - \prop_map_break: + \bool_set_true:N \l__fnpct_trailing_tokens_bool + \tl_map_break: } - { \bool_set_false:N \l__fnpct_multiple_footnotes_bool } - } - \bool_if:NTF \l__fnpct_multiple_footnotes_bool - { \tl_use:N \l__fnpct_multiple_true_tl } - { \tl_use:N \l__fnpct_multiple_false_tl } - } - -% check which mode is active: -\prg_new_conditional:Npnn \fnpct_punct_if_after: {T,TF} - { - \bool_if:nTF - { - \bool_xor_p:nn - { \l__fnpct_punct_after_bool } - { \l__fnpct_reverse_switch_bool } } + \bool_if:NTF \l__fnpct_trailing_tokens_bool { \prg_return_true: } { \prg_return_false: } } -% this is where the magic happens: -\cs_new_protected:Npn \fnpct_handle_punctuation:n #1 +% -------------------------------------------------------------------------- +% #1: token +\prg_new_protected_conditional:Npnn \__fnpct_check_trail:N #1 {T,F,TF} { - \fnpct_check_punctuation:TF - { - % this is need as some commands like biblatex's \autocite may in turn - % call \footnote. It then must not insert the pre-footnote-space: - \bool_gset_true:N \g__fnpct_after_punctuation_bool - % A: after=1 && reverse=0 - % after=0 && reverse=1 - % B: after=1 && reverse=1 - % after=0 && reverse=0 - \fnpct_punct_if_after:TF - { - \fnpct_no_break: - \skip_horizontal:N \l__fnpct_before_footnote_dim - } - { - \tl_use:N \l__fnpct_current_punct_mark_tl - \prop_get:NVNT \l__fnpct_punctuation_marks_after_prop - \l__fnpct_current_punct_mark_tl - \l__fnpct_tmpa_tl - { - \dim_set:Nn \l__fnpct_tmpa_dim { \l__fnpct_tmpa_tl } - \fnpct_no_break: - \skip_horizontal:N \l__fnpct_tmpa_dim - \fnpct_no_break: - \skip_horizontal:N \c_zero_skip - \fnpct_no_break: - } - } - #1 - \bool_gset_false:N \g__fnpct_after_punctuation_bool - \fnpct_punct_if_after:T - { - \fnpct_no_break: - \prop_get:NVNT \l__fnpct_punctuation_marks_before_prop - \l__fnpct_current_punct_mark_tl - \l__fnpct_tmpa_tl - { - \dim_set:Nn \l__fnpct_tmpa_dim { \l__fnpct_tmpa_tl } - \fnpct_no_break: - \skip_horizontal:N \l__fnpct_tmpa_dim - \fnpct_no_break: - \skip_horizontal:N \c_zero_skip - \fnpct_no_break: - } - \tl_use:N \l__fnpct_current_punct_mark_tl - } - \bool_set_false:N \l__fnpct_reverse_switch_bool - } + \bool_set_false:N \l_fnpct_trailing_action_bool + \tl_clear:N \l_fnpct_trailing_token_tl + \bool_if:NTF \l__fnpct_dont_mess_around_bool + { \prg_return_false: } { - % what about multiple footnotes? (their usage is discouraged with - % this package, but anyway...) - % this check should probably/maybe be removed (?!) - \fnpct_check_multiple:TF - { - \bool_set_true:N \l__fnpct_multiple_footnotes_bool - \fnpct_no_break: - \bool_if:NF \g__fnpct_after_punctuation_bool - { \skip_horizontal:N \l__fnpct_before_footnote_dim } - #1 - \fnpct_no_break: - \textsuperscript { \l__fnpct_multiple_footnote_separator_tl } - } + \tl_if_empty:NTF \l__fnpct_trailing_tokens_tl + { \prg_return_false: } { - % else insert space and then note - \bool_if:NTF \l__fnpct_multiple_footnotes_bool - { \bool_set_false:N \l__fnpct_multiple_footnotes_bool } + \tl_map_inline:Nn \l__fnpct_trailing_tokens_tl { - \fnpct_no_break: - \bool_if:NF \g__fnpct_after_punctuation_bool - { \skip_horizontal:N \l__fnpct_before_footnote_dim } + \token_if_eq_meaning:NNT #1 ##1 + { + \bool_set_true:N \l_fnpct_trailing_action_bool + \tl_set:Nn \l_fnpct_trailing_token_tl {##1} + \tl_map_break: + } } - #1 - \bool_set_false:N \l__fnpct_reverse_switch_bool + \bool_if:NTF \l_fnpct_trailing_action_bool + { \prg_return_true: } + { \prg_return_false: } } } } - -% #1: original command -% #2: optional argument of original command -% #3: second optional argument of original command -% #4: mandatory argument of original command -% #5: boolean flag for starred version -\cs_new_protected:Npn \fnpct_handle_note:Nnnnn #1#2#3#4#5 +% #1: class name +\prg_new_protected_conditional:Npnn \fnpct_if_class:n #1 {T,F,TF} { - % if a punctuation mark follows remove it, insert dot, skip back - % and then insert footnote - \bool_if:NF \l__fnpct_dont_mess_around_bool + \bool_if:NTF \l_fnpct_trailing_action_bool { - \IfBooleanT {#5} - { \bool_set_true:N \l__fnpct_reverse_switch_bool } - } - \fnpct_handle_punctuation:n - { - \fnpct_write_note:Nnnn #1 {#2} {#3} {#4} - \fnpct_write_inner:N #1 + \prop_get:NVN \l__fnpct_trailing_classes_prop + \l_fnpct_trailing_token_tl + \l__fnpct_tmpa_tl + \tl_if_eq:VnTF \l__fnpct_tmpa_tl {#1} + { \prg_return_true: } + { \prg_return_false: } } + { \prg_return_false: } } -\cs_generate_variant:Nn \fnpct_handle_note:Nnnnn { cnnnn } -% -------------------------------------------------------------------------- -% MULTIPLE FOOTNOTES -% #1: original note command -% #2: star -% #3: multiple notes separated by \l__fnpct_multiple_footnotes_delimiter_tl -\cs_new_protected:Npn \fnpct_mult_note:Nnn #1#2#3 +% #1: action name +\prg_new_protected_conditional:Npnn \fnpct_if_action:n #1 {T,F,TF} { - \bool_if:NF \l__fnpct_dont_mess_around_bool + \bool_if:NTF \l_fnpct_trailing_action_bool { - \IfBooleanT {#2} - { \bool_set_true:N \l__fnpct_reverse_switch_bool } + \prop_get:NVN \l__fnpct_trailing_actions_prop + \l_fnpct_trailing_token_tl + \l__fnpct_tmpa_tl + \tl_if_eq:VnTF \l__fnpct_tmpa_tl {#1} + { \prg_return_true: } + { \prg_return_false: } } - % split input: - \seq_set_split:NVn \l__fnpct_multiple_footnotes_seq - \l__fnpct_multiple_footnotes_delimiter_tl - {#3} - \fnpct_handle_punctuation:n - { \fnpct_write_notes:NN #1 \l__fnpct_multiple_footnotes_seq } - + { \prg_return_false: } } -\cs_generate_variant:Nn \fnpct_mult_note:Nnn {cnn} -% #1: original note command -% #2: sequence variable holding the note arguments -\cs_new_protected:Npn \fnpct_write_notes:NN #1#2 - { - \int_zero:N \l__fnpct_multiple_notes_int - \seq_map_inline:Nn #2 - { - \__fnpct_read_note_with_option:w ##1 \q_stop {#1} - \int_incr:N \l__fnpct_multiple_notes_int - } - } +% -------------------------------------------------------------------------- +% saving and using the note commands: +\cs_new:Npn \__fnpct_remove_backslash:N #1 + { \exp_after:wN \use_none:n \token_to_str:N #1 } -% this shouldn't be a document command but is a really easy way to make -% biblatex's \footcite et.al. compatible with the `multiple' option -% #1: optional star => only invoke \footnotetext -% #2: optional argument to original note command -% #3: second optional argument to original note command -% #4: mandatory argument to original note command -% #5: original note command -\NewDocumentCommand \__fnpct_read_note_with_option:w { soo+u{\q_stop}m } +% this is dangerous - it relies on undocumented innards of xparse - however, +% it should probably be rather safe, anyway: +\cs_new_protected:Npn \fnpct_save_note_command:N #1 { - \bool_if:nT - { - \int_compare_p:n { \l__fnpct_multiple_notes_int > 0 } - && - \int_compare_p:n - { - \l__fnpct_multiple_notes_int - < - \seq_count:N \l__fnpct_multiple_footnotes_seq - } - } - { - \IfBooleanTF {#1} - { \tex_unskip:D } - { \textsuperscript { \l__fnpct_multiple_footnote_separator_tl } } + \cs_undefine:c {fnpct_original_ \__fnpct_remove_backslash:N #1 :w} + \cs_if_exist:cTF { \__fnpct_remove_backslash:N #1 ~ code } + {% xparse command + \cs_new_eq:cc + { fnpct_original_ \__fnpct_remove_backslash:N #1 :w } + { \__fnpct_remove_backslash:N #1 ~ code } } - \IfBooleanTF {#1} { - % TODO: maybe provide option to change \footnotetext? Or do it - % automatically? - \bool_gset_true:N \g__fnpct_only_text_bool - \IfNoValueTF {#2} - { \footnotetext {#4} } - { \footnotetext [#2] {#4} } + \cs_if_exist:cTF { \__fnpct_remove_backslash:N #1 ~ } + {% robust command + \cs_new_eq:cc + { fnpct_original_ \__fnpct_remove_backslash:N #1 :w } + { \__fnpct_remove_backslash:N #1 ~ } + } + { \cs_new_eq:cN { fnpct_original_ \__fnpct_remove_backslash:N #1 :w } #1 } } - { \fnpct_write_note:Nnnn #5 {#2} {#3} {#4} } - \fnpct_write_inner:N #5 + \seq_put_right:Nn \l__fnpct_adapted_commands_seq {#1} + \fnpct_set_counter_name:Nx #1 { \__fnpct_remove_backslash:N #1 } } -% -------------------------------------------------------------------------- -% NESTED FOOTNOTES: -% 1 layer of nesting... -% this shouldn't be a document command! But for the time being I'll stick to -% this easy solution... -\NewDocumentCommand \fnpct_inner_footnote:w {o+m} +\cs_new_protected:Npn \fnpct_set_counter_name:Nn #1#2 + { \cs_set:cpn { fnpct_ \__fnpct_remove_backslash:N #1 _counter: } {#2} } +\cs_generate_variant:Nn \fnpct_set_counter_name:Nn {c,Nx} + +\cs_new:Npn \__fnpct_counter:N #1 + { \use:c { fnpct_ \__fnpct_remove_backslash:N #1 _counter: } } + +\hook_new:n {fnpct/rangesetup} + +\cs_new_protected:Npn \fnpct_use_note_command:N #1 { - \IfNoValueTF {#1} + \fnpct_if_debug:T + { \iow_term:x { fnpct~ info:~ \exp_not:N #1 \msg_line_context:} } + \tl_gset:Nx \g__fnpct_this_note_tl { \__fnpct_remove_backslash:N #1 } + \cs_if_exist:cTF {fnpct_original_ \__fnpct_remove_backslash:N #1 :w} { - % TODO: maybe detect what type of note we're in and use the appropriate mark? - % Or provide a user interface to choose the appropriate mark? - \fnpct_orig_footnotemark:w - \prop_gput:Nxn \g__fnpct_inner_footnote_prop { \thefootnote } {#2} - \bool_if:NT \l__fnpct_hyperref_bool + \fnpct_inside_range:TF { - \prop_gput:Nxo \g__fnpct_inner_footnote_hyperref_prop - { \thefootnote } { \Hy@footnote@currentHref } + \refstepcounter { \__fnpct_counter:N #1 } + \tl_set_eq:NN \l__fnpct_current_tl #1 + \hook_use:n {fnpct/rangesetup} + \use:c { \__fnpct_remove_backslash:N #1 text } } + { \use:c {fnpct_original_ \__fnpct_remove_backslash:N #1 :w} } } + { \msg_error:nnn {fnpct} {command-not-adapted} {#1} } + } +\cs_generate_variant:Nn \fnpct_use_note_command:N {c} + +\prg_new_conditional:Npnn \fnpct_if_current:N #1 {T,F,TF} + { + \tl_if_eq:NNTF \l__fnpct_current_tl #1 + { \prg_return_true: } + { \prg_return_false: } + } +\prg_generate_conditional_variant:Nnn \fnpct_if_current:N {c} {T} + +% -------------------------------------------------------------------------- +% action macros +\prg_new_conditional:Npnn \fnpct_if_collection: {p,T,F,TF} + { + \bool_if:NTF \l__fnpct_collection_bool + { \prg_return_true: } + { \prg_return_false: } + } + +\prg_new_conditional:Npnn \fnpct_if_ranges: {T,F,TF} + { + \bool_if:NTF \l__fnpct_ranges_bool + { \prg_return_true: } + { \prg_return_false: } + } + +\prg_new_conditional:Npnn \fnpct_inside_range: {T,F,TF} + { + \bool_if:NTF \l__fnpct_inside_range_bool + { \prg_return_true: } + { \prg_return_false: } + } + +% swapping: +% #1: all the new footnote code, arguments already read +% #2: the trailing punctuation +\cs_new_protected:Npn \fnpct_swap:nn #1#2 + { + \fnpct_if_collection:TF { - \fnpct_orig_footnotemark:w [#1] - \prop_gput:Nnn \g__fnpct_inner_footnote_prop {#1} {#2} - \bool_if:NT \l__fnpct_hyperref_bool + \__fnpct_swap:nn { - \prop_gput:Nno \g__fnpct_inner_footnote_hyperref_prop - {#1} { \Hy@footnote@currentHref } + \fnpct_before: + \fnpct_print_collection: + \fnpct_print_note:w #1 + \fnpct_after: } + {#2} } + { \__fnpct_swap:nn {#1} {#2} } } -\cs_new_protected:Npn \fnpct_write_inner:N #1 +\cs_new_protected:Npn \__fnpct_swap:nn #1#2 { - \token_if_eq_meaning:NNF #1 \fnpct_inner_footnote:w + \fnpct_if_switched:TF { - \prop_map_inline:Nn \g__fnpct_inner_footnote_prop - { - \footnotetext [##1] - { - \bool_if:NT \l__fnpct_hyperref_bool - { - \prop_get:NnN \g__fnpct_inner_footnote_hyperref_prop - {##1} \l__fnpct_tmpa_tl - \Hy@raisedlink - { \exp_args:NV \hyper@@anchor \l__fnpct_tmpa_tl } - } - ##2 - } - } - \prop_gclear:N \g__fnpct_inner_footnote_prop + \use:nn + { \fnpct_skip_nobreak:N \l__fnpct_before_footnote_dim #1 } + { \fnpct_add_punctuation_space:n {before} #2 } } + { \use_ii_i:nn {#1} {#2} } } -\NewDocumentCommand \writeinnernotes {} - { \fnpct_write_inner:N X } +\cs_new:Npn \fnpct_print_note:w \fnpct_before: #1 \fnpct_after: +{ \exp_not:n { #1 } } -% -------------------------------------------------------------------------- -% MANUAL KERNING: -\cs_new_protected:Npn \fnpct_kfp: +% multiple footnotes and ranges: +\cs_new_protected:Npn \__fnpct_collect:n #1 { - \fnpct_no_break: - \prop_get:NnNT \l__fnpct_punctuation_marks_before_prop {.} - \l__fnpct_tmpa_tl - { \dim_set:Nn \l__fnpct_tmpa_dim { \l__fnpct_tmpa_tl } } - \prop_get:NnNT \l__fnpct_punctuation_marks_after_prop {.} - \l__fnpct_tmpb_tl - { \dim_set:Nn \l__fnpct_tmpb_dim { \l__fnpct_tmpb_tl } } - \bool_if:NTF \l__fnpct_punct_after_bool - { \skip_horizontal:N \l__fnpct_tmpa_dim } - { \skip_horizontal:N \l__fnpct_tmpb_dim } + \int_incr:N \l__fnpct_collection_int + \seq_put_right:Nx \l__fnpct_collection_seq { \fnpct_print_note:w #1 } } -\cs_new_protected:Npn \fnpct_kfc: +% #1: all the new footnote code, arguments already read +% #2: e.g. the token \footnote +\cs_new_protected:Npn \fnpct_collect:nn #1#2 { - \fnpct_no_break: - \prop_get:NnNT \l__fnpct_punctuation_marks_before_prop {,} - \l__fnpct_tmpa_tl - { \dim_set:Nn \l__fnpct_tmpa_dim { \l__fnpct_tmpa_tl } } - \prop_get:NnNT \l__fnpct_punctuation_marks_after_prop {,} - \l__fnpct_tmpb_tl - { \dim_set:Nn \l__fnpct_tmpb_dim { \l__fnpct_tmpb_tl } } - \bool_if:NTF \l__fnpct_punct_after_bool - { \skip_horizontal:N \l__fnpct_tmpa_dim } - { \skip_horizontal:N \l__fnpct_tmpb_dim } + \fnpct_if_collection:F + { + % we're starting a collection + \seq_clear:N \l__fnpct_collection_seq + \int_set:Nn \l__fnpct_collection_int {1} + \bool_set_true:N \l__fnpct_collection_bool + } + \__fnpct_collect:n {#1} + #2 } -\NewDocumentCommand \kfp {} { \fnpct_kfp: } -\NewDocumentCommand \kfc {} { \fnpct_kfc: } - -% -------------------------------------------------------------------------- -% NORMAL MARKS: -\AtBeginDocument +\cs_new_protected:Npn \fnpct_print_collection: { - \bool_if:NT \l__fnpct_normal_marks_bool + \bool_set_false:N \l__fnpct_collection_bool + \bool_set_true:N \l__fnpct_end_collection_bool + % DEBUG: + \fnpct_if_ranges:TF { - \cs_if_exist:NF \KOMAoption - { \RequirePackage { scrextend } } - \deffootnote - [ \l__fnpct_normal_mark_width_dim ] - { \l__fnpct_normal_indent_dim } - { \l__fnpct_normal_parindent_dim } - { \thefootnotemark . \enskip } + \seq_item:Nn \l__fnpct_collection_seq {1} + \seq_pop_left:NN \l__fnpct_collection_seq \l__fnpct_tmpa_tl + \tl_clear:N \l__fnpct_tmpa_tl + \bool_set_true:N \l__fnpct_inside_range_bool + \seq_use:Nn \l__fnpct_collection_seq { } + \bool_set_false:N \l__fnpct_inside_range_bool + \int_compare:nNnTF \l__fnpct_collection_int = {2} + { \__fnpct_separate: } + { \l__fnpct_range_tl } } + { + \seq_use:Nn \l__fnpct_collection_seq { \__fnpct_separate: } + \__fnpct_separate: + } + } + +\cs_new_protected:Npn \__fnpct_separate: + { + \bool_if:NTF \g__fnpct_text_bool + { \bool_gset_false:N \g__fnpct_text_bool } + { \l__fnpct_separate_tl } + } + +% -------------------------------------------------------------------------- +% define some classes and actions: +\fnpct_new_class:n {punctuation} +\fnpct_new_class:n {note} + +\fnpct_new_action:nnnnn {dot} {punctuation} {-.16em} {-0.06em} { \fnpct_swap:nn } +\fnpct_new_action:nnnnn {comma} {punctuation} {-.16em} {-0.06em} { \fnpct_swap:nn } +\fnpct_new_action:nnnnn {collect} {note} {0pt} {0pt} { \fnpct_collect:nn } + +\fnpct_new_trailing_token:Nn . {dot} +\fnpct_new_trailing_token:Nn , {comma} + +% #1: default before dim +% #2: token +% #3: default after dim +% #4: name +\NewDocumentCommand \AddPunctuation {O{0pt}mO{0pt}m} + { + \fnpct_new_action:nnnnn {#4} {punctuation} {#1} {#3} { \fnpct_swap:nn } + \fnpct_new_trailing_token:Nn #2 {#4} + \keys_set:nn {fnpct} { activate-trailing-tokens = #2 } } % -------------------------------------------------------------------------- -% LET'S MAKE IT EASIER TO ADAPT EXISTING FUNCTIONS: -% COPY, RENEW AND CREATE MULT +% build up the frame for the adapted note commands: -\prg_new_conditional:Npnn \fnpct_if_adapted:N #1 {p,T,F,TF} +\prg_new_conditional:Npnn \fnpct_if_switched: {p,T,F,TF} { - \prop_if_in:NnTF \g__fnpct_adapted_notes_prop {#1} + \bool_if:NTF \l__fnpct_switched_bool { \prg_return_true: } { \prg_return_false: } } -\cs_new_protected:Npn \fnpct_add_to_adapted:NN #1#2 - { - % \tl_show:n {1:~#1} \tl_show:n {2:~#2} - \prop_gput:Nnn \g__fnpct_adapted_notes_prop {#1} {#2} - } +\cs_new_protected:Npn \__fnpct_execute: {} -% standard \footnote[<mark>]{<text>} like commands -% #1: old new name -% #2: internal name of old definition -% #3: mult-variant -% -% \footnote[<mark>]{<text>} like: -\cs_new_protected:Npn \fnpct_renew_and_mult:NNN #1#2#3 +% #1: boolean +\cs_new_protected:Npn \fnpct_begin: + { \__fnpct_check_after_end:w } + +% #1: code +\cs_new_protected:Npn \__fnpct_check_after_end:w #1 \fnpct_end: { - \fnpct_if_adapted:NF #1 + \cs_set_protected:Npn \__fnpct_execute: { - \fnpct_add_to_adapted:NN #1#2 - \cs_new_eq:NN #2#1 - \fnpct_create_mult_variant:NN #3#2 - \bool_if:NTF \l__fnpct_multiple_default_bool - { \cs_set_eq:NN #1#3 } + \__fnpct_check_trail:NTF \l_peek_token { - \RenewDocumentCommand #1 {so+m} - { \fnpct_handle_note:Nnnnn #2 {##2} { \q_no_value } {##3} {##1} } + \prop_get:NVN \l__fnpct_trailing_actions_prop + \l_fnpct_trailing_token_tl + \l_fnpct_action_tl + \fnpct_do_action:Vnw \l_fnpct_action_tl {#1} } - } - } -\cs_generate_variant:Nn \fnpct_renew_and_mult:NNN {ccc,NcN} - -% \footnote{<text>} like: -\cs_new_protected:Npn \fnpct_renew_and_mult_no_opt:NNN #1#2#3 - { - \fnpct_if_adapted:NF #1 - { - \fnpct_add_to_adapted:NN #1#2 - \cs_new_eq:NN #2#1 - \fnpct_create_mult_variant:NN #3#2 - \bool_if:NTF \l__fnpct_multiple_default_bool - { \cs_set_eq:NN #1#3 } { - \RenewDocumentCommand #1 {s+m} + % no trailing punctuation + \bool_lazy_or:nnT + { \fnpct_if_collection_p: } + { \fnpct_if_switched_p: } { - \fnpct_handle_note:Nnnnn #2 { \q_no_value } { \q_no_value } - {##2} {##1} + \fnpct_skip_nobreak:N \l__fnpct_before_footnote_dim + \fnpct_if_collection:T { \fnpct_print_collection: } } + #1 } + \fnpct_end: } + \peek_after:Nw \__fnpct_execute: } -\cs_generate_variant:Nn \fnpct_renew_and_mult_no_opt:NNN {Nc,ccc} -% renew but don't create mult-variant: -% \footnote[<mark>]{<text>} like: -\cs_new_protected:Npn \fnpct_renew:NN #1#2 +\cs_new_protected:Npn \fnpct_end: { } + +\cs_new_protected:Npn \fnpct_before: { - \fnpct_if_adapted:NF #1 + \bool_if:NF \l__fnpct_dont_mess_around_bool { - \fnpct_add_to_adapted:NN #1#2 - \cs_new_eq:NN #2#1 - \RenewDocumentCommand #1 {so+m} - { \fnpct_handle_note:Nnnnn #2 {##2} { \q_no_value } {##3} {##1} } + \fnpct_if_switched:F + { \fnpct_add_punctuation_space:n {after} } + \bool_if:NF \l_fnpct_trailing_action_bool + { % no punctiation following + \bool_if:NF \l__fnpct_end_collection_bool + { \fnpct_skip_nobreak:N \l__fnpct_before_footnote_dim } + } } } -\cs_generate_variant:Nn \fnpct_renew:NN {cc,Nc} -% new -\cs_new_protected:Npn \fnpct_new:NN #1#2 +\cs_new_protected:Npn \fnpct_add_punctuation_space:n #1 { - \fnpct_if_adapted:NF #1 + \fnpct_if_class:nT {punctuation} { - \fnpct_add_to_adapted:NN #1#2 - \NewDocumentCommand #1 {so+m} - { \fnpct_handle_note:Nnnnn #2 {##2} { \q_no_value } {##3} {##1} } + \fnpct_foreach_action:nn {punctuation} + { + \fnpct_if_action:nT {##1} + { + \fnpct_skip_nobreak:c {l__fnpct_#1_##1_dim} + \fnpct_action_break: + } + } } } -\cs_generate_variant:Nn \fnpct_new:NN {cc,Nc} - -% \note[<mark>][<oarg>]{<text>} like: -\cs_new_protected:Npn \fnpct_renew_and_mult_opt:NNN #1#2#3 + +\cs_new_protected:Npn \fnpct_after: { - \fnpct_if_adapted:NF #1 + \bool_if:NF \l__fnpct_dont_mess_around_bool { - \fnpct_add_to_adapted:NN #1#2 - \cs_new_eq:NN #2#1 - \fnpct_create_mult_variant:NN #3#2 - \bool_if:NTF \l__fnpct_multiple_default_bool - { \cs_set_eq:NN #1#3 } + \fnpct_if_switched:T { - \RenewDocumentCommand #1 {soo+m} - { \fnpct_handle_note:Nnnnn #2 {##2} {##3} {##4} {##1} } + \fnpct_if_class:nT {punctuation} + { + \bool_set_false:N \l__fnpct_collection_bool + \fnpct_foreach_action:nn {punctuation} + { + \fnpct_if_action:nT {##1} + { + \fnpct_skip_nobreak:c {l__fnpct_before_##1_dim} + \fnpct_action_break: + } + } + } + \bool_set_false:N \l__fnpct_end_collection_bool + \bool_set_false:N \l__fnpct_switched_bool } } } -\cs_generate_variant:Nn \fnpct_renew_and_mult_opt:NNN {ccc,NcN} -\cs_new_protected:Npn \fnpct_renew_opt:NN #1#2 +% #1: command +% #2: argument spec +% #3: code where #NOTE refers to the original note + +\cs_new_protected:Npn \fnpct_adapt_note:Nnn #1#2#3 { \fnpct_if_adapted:NF #1 { - \fnpct_add_to_adapted:NN #1#2 - \cs_new_eq:NN #2#1 - \RenewDocumentCommand #1 {soo+m} - { \fnpct_handle_note:Nnnnn #2 {##2} {##3} {##4} {##1} } + \fnpct_save_note_command:N #1 + \fnpct_new_trailing_token:Nn #1 {collect} + \keys_set:nn {fnpct} { activate-trailing-tokens = {#1} } + } + \tl_set:Nn \l__fnpct_tmpa_tl {#3} + \regex_replace_all:nnN {\cP\#\cP\#} {$$$$} \l__fnpct_tmpa_tl + \regex_replace_all:nnN {\cP\#8} {\cP\#9} \l__fnpct_tmpa_tl + \regex_replace_all:nnN {\cP\#7} {\cP\#8} \l__fnpct_tmpa_tl + \regex_replace_all:nnN {\cP\#6} {\cP\#7} \l__fnpct_tmpa_tl + \regex_replace_all:nnN {\cP\#5} {\cP\#6} \l__fnpct_tmpa_tl + \regex_replace_all:nnN {\cP\#4} {\cP\#5} \l__fnpct_tmpa_tl + \regex_replace_all:nnN {\cP\#3} {\cP\#4} \l__fnpct_tmpa_tl + \regex_replace_all:nnN {\cP\#2} {\cP\#3} \l__fnpct_tmpa_tl + \regex_replace_all:nnN {\cP\#1} {\cP\#2} \l__fnpct_tmpa_tl + \regex_replace_all:nxN + {\cP\#NOTE} + { + \exp_not:N \c{fnpct_use_note_command:N} + \exp_not:N \c{\__fnpct_remove_backslash:N #1} + } + \l__fnpct_tmpa_tl + % we need to double inner arguments yet one more, so it can appear inside + % the replacement text of \__fnpct_execute: + \regex_replace_all:nnN {\$\$\$\$} {\cP\#\cP\#\cP\#\cP\#} \l__fnpct_tmpa_tl + \tl_put_left:Nn \l__fnpct_tmpa_tl { \fnpct_start:w } + \tl_put_right:Nn \l__fnpct_tmpa_tl { \fnpct_stop: } + \use:x + { + \exp_not:n { \RenewDocumentCommand #1 {s#2} } + { + \exp_not:n { \fnpct_reverse:n {##1} } + \exp_not:V \l__fnpct_tmpa_tl + } } } -\cs_generate_variant:Nn \fnpct_renew_opt:NN {cc,Nc} +\cs_generate_variant:Nn \fnpct_adapt_note:Nnn {c} -% \note{<arg>} like -\cs_new_protected:Npn \fnpct_renew_no_opt:NN #1#2 +\cs_new_protected:Npn \fnpct_reverse:n #1 { - \fnpct_if_adapted:NF #1 - { - \fnpct_add_to_adapted:NN #1#2 - \cs_new_eq:NN #2#1 - \RenewDocumentCommand #1 {s+m} - { \fnpct_handle_note:Nnnnn #2 { \q_no_value } { \q_no_value } {##2} {##1} } - } + \bool_if:NTF \l__fnpct_reverse_bool + { \bool_if:nF } + { \bool_if:NT } + {#1} { \bool_set_true:N \l__fnpct_switched_bool } } -\cs_generate_variant:Nn \fnpct_renew_no_opt:NN {cc,Nc} -% \note like -\cs_new_protected:Npn \fnpct_renew_no_arg:NN #1#2 +% #1: code +\cs_new_protected:Npn \fnpct_start:w #1 \fnpct_stop: { - \fnpct_if_adapted:NF #1 - { - \fnpct_add_to_adapted:NN #1#2 - \cs_new_eq:NN #2#1 - \RenewDocumentCommand #1 {s} - { \fnpct_handle_note:Nnnnn #2 { \q_no_value } { \q_no_value } { } {##1} } - } + \fnpct_begin: + \fnpct_before: + \group_begin: + #1 + \group_end: + \fnpct_after: + \fnpct_end: } -\cs_generate_variant:Nn \fnpct_renew_no_arg:NN {cc} -% create mult-variant -\cs_new_protected:Npn \fnpct_create_mult_variant:NN #1#2 +\cs_new_protected:Npn \fnpct_text: { - \NewDocumentCommand #1 {s+m} - { \fnpct_mult_note:Nnn #2 {##1} {##2} } + \bool_set_false:N \l__fnpct_inside_range_bool + \bool_gset_true:N \g__fnpct_text_bool } -% \footnotemark[<mark>] like commands: -\cs_new_protected:Npn \fnpct_renew_mark:NN #1#2 +% -------------------------------------------------------------------------- +% #1: note command +% #2: arguments +% #3: counter name +% #4: code +\NewDocumentCommand \AdaptNote {mmom} { - \fnpct_if_adapted:NF #1 - { - \fnpct_add_to_adapted:NN #1#2 - \cs_new_eq:NN #2#1 - \RenewDocumentCommand #1 {so} - { \fnpct_handle_note:Nnnnn #2 {##2} { \q_no_value } { } {##1} } - } + \fnpct_adapt_note:Nnn #1 {#2} {#4} + \IfNoValueF {#3} + { \fnpct_set_counter_name:Nn #1 {#3} } } -\cs_generate_variant:Nn \fnpct_renew_mark:NN {cc,Nc} -% user commands: -\NewDocumentCommand \AdaptNote {mm} +\NewDocumentCommand \AdaptNoteName {mmom} { - \cs_if_exist:cTF { fnpct_orig_ \cs_to_str:N #1 :w } - { \fnpct_message:nx {already-adapted} {#1} } - { \fnpct_renew_and_mult:NcN #1 { fnpct_orig_ \cs_to_str:N #1 :w } #2 } + \fnpct_adapt_note:cnn {#1} {#2} {#4} + \IfNoValueF {#3} + { \fnpct_set_counter_name:cn {#1} {#3} } } -\NewDocumentCommand \AdaptNoteNoMult {m} +\NewDocumentCommand \AdaptText {mmm} { - \cs_if_exist:cTF { fnpct_orig_ \cs_to_str:N #1 :w } - { \fnpct_message:nx {already-adapted} {#1} } - { \fnpct_renew:Nc #1 { fnpct_orig_ \cs_to_str:N #1 :w } } + \fnpct_adapt_note:Nnn #1 {#2} + { \fnpct_text: #3 } } -\NewDocumentCommand \AdaptNoteOpt {mm} +\NewDocumentCommand \innernote {+m} + { \msg_warning:nn {fnpct} {command-removed} \use:n {#1} } + +\NewExpandableDocumentCommand \ifcurrentnoteTF {m} + { \fnpct_if_current:NTF #1 } + +\NewExpandableDocumentCommand \ifcurrentnoteT {m} + { \fnpct_if_current:NT #1 } + +\NewExpandableDocumentCommand \ifcurrentnoteF {m} + { \fnpct_if_current:NF #1 } + +% -------------------------------------------------------------------------- +% OPTIONS +\NewDocumentCommand \setfnpct {m} + { \keys_set:nn {fnpct} {#1} } + +\cs_new_protected:Npn \fnpct_deprecate_option:n #1 + { \msg_warning:nnVn {fnpct} {option-deprecated} \l_keys_key_str {#1} } + +\cs_new_protected:Npn \fnpct_deprecate_option: + { \msg_warning:nnV {fnpct} {option-deprecated} \l_keys_key_str } + +\keys_define:nn {fnpct} { - \cs_if_exist:cTF { fnpct_orig_ \cs_to_str:N #1 :w } - { \fnpct_message:nx {already-adapted} {#1} } - { \fnpct_renew_and_mult_opt:NcN #1 { fnpct_orig_ \cs_to_str:N #1 :w } #2 } + add-trailing-token .code:n = \AddPunctuation #1 , + activate-trailing-tokens .code:n = + \tl_map_inline:nn {#1} { \fnpct_activate_trailing_token:n {##1} } , + activate-trailing-tokens .initial:n = {.,} , + deactivate-trailing-tokens .code:n = + \tl_map_inline:nn {#1} { \fnpct_deactivate_trailing_token:n {##1} } , + before-footnote-space .dim_set:N = \l__fnpct_before_footnote_dim , + before-footnote-space .initial:n = .06em , + ranges .bool_set:N = \l__fnpct_ranges_bool , + ranges .initial:n = false , + keep-ranges .bool_set:N = \l__fnpct_keep_ranges_bool , + keep-ranges .initial:n = false , + dont-mess-around .bool_set:N = \l__fnpct_dont_mess_around_bool , + dont-mess-around .initial:n = false , + mult-fn-delim .code:n = + \tl_set:Nn \l__fnpct_multiple_footnotes_delimiter_tl {#1} , + separation-symbol .code:n = + \renewcommand* \multfootsep {#1} , + range-symbol .code:n = + \renewcommand* \multfootrange {#1} , + print-separation .tl_set:N = \l__fnpct_separate_tl , + print-separation .initial:n = \textsuperscript { \multfootsep } , + print-range .tl_set:N = \l__fnpct_range_tl , + print-range .initial:n = \textsuperscript { \multfootrange } , + reverse .bool_set:N = \l__fnpct_reverse_bool , + after-punct-space .code:n = + \fnpct_foreach_action:nn {punctuation} + { \keys_set:nn {fnpct} { after-##1-space = #1 } } , + before-punct-space .code:n = + \fnpct_foreach_action:nn {punctuation} + { \keys_set:nn {fnpct} { before-##1-space = #1 } } } -\NewDocumentCommand \AdaptNoteOptNoMult {m} +% deprecate options of earlier version unless it still exists: +\clist_map_inline:nn { - \cs_if_exist:cTF { fnpct_orig_ \cs_to_str:N #1 :w } - { \fnpct_message:nx {already-adapted} {#1} } - { \fnpct_renew_opt:Nc #1 { fnpct_orig_ \cs_to_str:N #1 :w } } + bigfoot-default-top , + strict , + after-comma-space , + after-dot-space , + before-comma-space , + before-dot-space , + after-punct-space , + before-punct-space , + before-footnote-space , + french-before-footnote-space , + punct-after , + dont-mess-around , + mult-fn-delim , + mult-fn-sep , + multiple , + normal-marks , + normal-mark-width , + normal-indent , + normal-parindent , + verb-format , + add-punct-marks , + remove-punct-marks , } + { + \keys_if_exist:nnF {fnpct} {#1} + { \keys_define:nn {fnpct} { #1 .code:n = \fnpct_deprecate_option: } } + } + +% -------------------------------------------------------------------------- +% define \multfootnote and friends for some transition period -\NewDocumentCommand \AdaptNoteNoOpt {mm} +\cs_new_protected:Npn \fnpct_create_mult_variant:N #1 { - \cs_if_exist:cTF { fnpct_orig_ \cs_to_str:N #1 :w } - { \fnpct_message:nx {already-adapted} {#1} } - { \fnpct_renew_and_mult_no_opt:NcN #1 { fnpct_orig_ \cs_to_str:N #1 :w } #2 } + \exp_args:Nc \NewDocumentCommand + { mult \__fnpct_remove_backslash:N #1 } + { sm } + { + \seq_set_split:NVn \l__fnpct_tmpa_seq + \l__fnpct_multiple_footnotes_delimiter_tl + {##2} + \tl_clear:N \l__fnpct_tmpa_tl + \seq_map_inline:Nn \l__fnpct_tmpa_seq + { + \tl_put_right:Nx \l__fnpct_tmpa_tl + { \exp_not:n {#1} \IfBooleanT{##1}{*} \exp_not:n {{####1}} } + } + \l__fnpct_tmpa_tl + } } +\cs_generate_variant:Nn \fnpct_create_mult_variant:N {c} + +\NewDocumentCommand \MultVariant {m} + { \fnpct_create_mult_variant:N #1 } + +\NewDocumentCommand \MultVariantName {m} + { \fnpct_create_mult_variant:c {#1} } -\NewDocumentCommand \AdaptNoteNoOptNoMult {m} +% -------------------------------------------------------------------------- +% TAKE CARE OF FRENCH SETTINGS +\RequirePackage {translations} +\hook_gput_code:nnn {begindocument/end} {fnpct} { - \cs_if_exist:cTF { fnpct_orig_ \cs_to_str:N #1:w } - { \fnpct_message:nx {already-adapted} {#1} } - { \fnpct_renew_no_opt:Nc #1 { fnpct_orig_ \cs_to_str:N #1:w } } + \ifcurrentbaselanguage {French} + { + \cs_set_eq:NN \@footnotemark \@footnotemarkORI + \StandardFootnotes + \keys_set:nn {fnpct} { before-footnote-space = .16667em } + } + {} } -\NewDocumentCommand \AdaptNoteMark {m} +% -------------------------------------------------------------------------- + +\hook_gput_code:nnn {begindocument} {fnpct} { - \cs_if_exist:cTF { fnpct_orig_ \cs_to_str:N #1 :w } - { \fnpct_message:nx {already-adapted} {#1} } - { \fnpct_renew_mark:Nc #1 { fnpct_orig_ \cs_to_str:N #1 :w } } + \fnpct_if_class_loaded:nTF {memoir} + { \renewcommand* } + { \providecommand* } + \multfootsep {,} + \providecommand* \multfootrange {--} + \tl_set:Nn \l__fnpct_range_tl { \textsuperscript { \multfootrange } } } % -------------------------------------------------------------------------- % DO THE REDEFINING: % -% `bigfoot' loads `manyfoot' which saves its footnote classes in a 2e list: -\str_const:Nn \c__fnpct_footins_str {\footins} -\str_remove_once:Nn \c__fnpct_footins_str {~} +% before we start make the testing more comfortable: +\cs_new_protected:Npn \fnpct_treatment:nn #1#2 + { \fnpct_if_package_loaded:nT {#1} {#2} } + +\cs_new_protected:Npn \fnpct_special_treatment:nn #1#2 + { + \fnpct_if_package_loaded:nTF {#1} {#2} + { \hook_gput_code:nnn {package/after/#1} {fnpct} {#2} } + } + +% `manyfoot' (loaded by `bigfoot') saves its footnote classes in a 2e list: +\str_new:N \l__fnpct_footins_str +\str_set:Nn \l__fnpct_footins_str {\footins} +\str_remove_once:Nn \l__fnpct_footins_str {~} \cs_new_protected:Npn \__fnpct_grab_second:Nnw #1#2#3 \q_stop { \str_set:Nn \l__fnpct_tmpa_str {#3} \str_remove_once:Nn \l__fnpct_tmpa_str {~} - \str_remove_once:NV \l__fnpct_tmpa_str \c__fnpct_footins_str + \str_remove_once:NV \l__fnpct_tmpa_str \l__fnpct_footins_str \seq_put_right:Nx #1 { \l__fnpct_tmpa_str } } \cs_new_protected:Npn \__fnpct_get_fnclasses:NN #1#2 { - \seq_set_split:NnV \l__fnpct_tmpa_seq {\@elt } #1 + \seq_set_split:NnV \l__fnpct_tmpa_seq { \@elt } #1 \seq_pop_left:NN \l__fnpct_tmpa_seq \l__fnpct_tmpa_tl \seq_map_inline:Nn \l__fnpct_tmpa_seq { \__fnpct_grab_second:Nnw #2 ##1 \q_stop } \seq_remove_duplicates:N #2 } -% before we start make the testing more comfortable: -\cs_new_protected:Npn \fnpct_treatment:nn #1#2 - { \fnpct_if_package_loaded:nT {#1} {#2} } - -\cs_new_protected:Npn \fnpct_special_treatment:nn #1#2 - { \fnpct_if_package_loaded:nTF {#1} {#2} { \AfterPackage* {#1} {#2} } } - -% and now get going: -\AtBeginDocument +% `fixfoot' package +\fnpct_special_treatment:nn {fixfoot} { - \fnpct_if_package_loaded:nTF {hyperref} - { \bool_set_true:N \l__fnpct_hyperref_bool } + % hook into \DeclareFixedFootnote so we can redefine all fixed footnotes + % defined be users + \seq_new:N \l__fnpct_footnote_fixfoot_seq + \cs_new_eq:NN \fnpct_new_fixnote:w \DeclareFixedFootnote + \RenewDocumentCommand \DeclareFixedFootnote {smm} { - \cs_if_exist:NF \AfterBeginDocument - { \cs_new:Npn \AfterBeginDocument #1 {#1} } + \seq_put_right:Nn \l__fnpct_footnote_fixfoot_seq {#2} + \IfBooleanTF {#1} + { \fnpct_new_fixnote:w * {#2} {#3} } + { \fnpct_new_fixnote:w {#2} {#3} } } - \AfterBeginDocument + } + +% `pagenote' package: +\fnpct_special_treatment:nn {pagenote} + { + \bool_new:N \l__fnpct_makepagenote_bool + \tl_put_left:Nn \makepagenote + { \bool_set_true:N \l__fnpct_makepagenote_bool } + } + +\fnpct_special_treatment:nn {sepfootnotes} + { + \cs_new_eq:NN \fnpct_sepfootnote_new:n \sep@new + \seq_new:N \l__fnpct_sepfootnotes_seq + \cs_set_protected:Npn \sep@new #1 { + \seq_put_right:Nn \l__fnpct_sepfootnotes_seq {#1} + \fnpct_sepfootnote_new:n {#1} + } + } + +\hook_gput_code:nnn {begindocument} {fnpct} + { + \fnpct_if_package_loaded:nT {hyperref} { - \AdaptNote \footnote \multfootnote - \AdaptNoteMark \footnotemark - \cs_if_exist:NT \footref - { \AdaptNoteNoOptNoMult \footref } - \fnpct_new:NN \innernote \fnpct_inner_footnote:w - %% the `endnotes' package: - \fnpct_treatment:nn {endnotes} + \fnpct_if_ranges:T { - \AdaptNote \endnote \multendnote - \AdaptNoteMark \endnotemark + \bool_if:NTF \l__fnpct_keep_ranges_bool + { \msg_warning:nn {fnpct} {keep-ranges-hyperref} } + { + \msg_warning:nn {fnpct} {ranges-hyperref} + \bool_set_false:N \l__fnpct_ranges_bool + \keys_define:nn {fnpct} + { ranges .code:n = \msg_warning:nn {fnpct} {ranges-disabled} } + } } - %% the `enotez' package: - \fnpct_treatment:nn {enotez} - { \AdaptNote \endnote \multendnote } - %% the `snotez' package: - \fnpct_treatment:nn {snotez} + } + %% LaTeX's defaults: + \fnpct_if_class_loaded:nTF {beamer} + { + \AdaptNote \footnote{d<>o+m} [\beamer@mpfn] { - \AdaptNoteOpt \sidenote \multsidenote - \AdaptNoteMark \sidenotemark + \IfNoValueTF{#1} + {\IfNoValueTF{#2}{#NOTE{#3}}{#NOTE[#2]{#3}}} + {\IfNoValueTF{#2}{#NOTE<#1>{#3}}{#NOTE<#1>[#2]{#3}}} } - %% the `parnotes' package: - \fnpct_treatment:nn {parnotes} - { \AdaptNote \parnote \multparnote } - %% the `pagenote' package: - \fnpct_treatment:nn {pagenote} + \AdaptNote \footnotemark {o} [\beamer@mpfn] + { \IfNoValueTF {#1} {#NOTE} {#NOTE[#1]} } + } + { + \AdaptNote \footnote {o+m} [\@mpfn] + { \IfNoValueTF {#1} {#NOTE{#2}} {#NOTE[#1]{#2}} } + \AdaptNote \footnotemark {o} [\@mpfn] + { \IfNoValueTF {#1} {#NOTE} {#NOTE[#1]} } + } + \fnpct_if_multiple:T { \MultVariant \footnote } + % TODO: should we adapt \thanks? Not with memoir, though... + % \AdaptNote \thanks {+m} { \cs_set_eq:NN \rlap \use:n #NOTE{#1} } + %% KOMA-Script and memoir: + \cs_if_exist:NT \footref + { \AdaptNote \footref {m} { #NOTE{#1} } } + %% snotez: + \fnpct_treatment:nn {snotez} + { + \AdaptNote \sidenote {d()oo+m} { - \bool_if:NTF \l__fnpct_makepagenote_bool - { \AdaptNote \pagenote \multpagenote } - { \msg_warning:nn {fnpct} {pagenote} } + \IfNoValueTF {#1} + { + \IfNoValueTF {#2} + {#NOTE{#4}} + { \IfNoValueTF {#3} {#NOTE[#2]{#4}} {#NOTE[#2][#3]{#4}} } + } + { \IfNoValueTF {#2} {#NOTE(#1){#4}} {#NOTE(#1)[#2]{#4}} } } - %% the `tablefootnote' package: - \fnpct_treatment:nn {tablefootnote} - { \AdaptNote \tablefootnote \multtablefootnote } - %% the `manyfoot' package (also loaded by `bigfoot'): - \fnpct_treatment:nn {manyfoot} + \AdaptNote \sidenotemark {o} [sidenote] + { \IfNoValueTF {#1} {#NOTE} {#NOTE[#1]} } + \fnpct_if_multiple:T { \MultVariant \sidenote } + } + % sidenotes: + \fnpct_treatment:nn {sidenotes} + { + % `sidenotes' implements its \sidenote in terms of the user + % commands \sidenotemark and \sidenotetext; this makes it quite + % difficult if not impossible to adapt its commands + \msg_warning:nnn {fnpct} {cannot-adapt} {sidenotes} + } + \bool_lazy_or:nnT + { \fnpct_if_class_loaded_p:n {tufte-handout} } + { \fnpct_if_class_loaded_p:n {tufte-book} } + { + \fnpct_if_ranges:TF { - \__fnpct_get_fnclasses:NN \MFL@list \l__fnpct_footnote_class_seq - \seq_map_inline:Nn \l__fnpct_footnote_class_seq + \msg_warning:nnnn {fnpct} {cannot-adapt-with-ranges} + {tufte-latex} { - \str_if_eq:nnTF {#1} {default} - { - \cs_if_exist:NT \footnotedefault - { - \fnpct_renew_and_mult:ccc {footnote#1} - {fnpct_orig_footnote#1:w} - {multfootnote#1} - \fnpct_renew_mark:cc {footnotemark#1} - {fnpct_orig_footnotemark#1:w} - } - } - { - \fnpct_renew_and_mult:ccc {footnote#1} - {fnpct_orig_footnote#1:w} - {multfootnote#1} - \fnpct_renew_mark:cc {footnotemark#1} - {fnpct_orig_footnotemark#1:w} - } + The~ command~ \sidenote~ misses~ a~ suitable~ \sidenotetext~ + version. } } - %% the `bigfoot' package: - \fnpct_special_treatment:nn {bigfoot} { - \cs_if_exist:NT \footnotedefault + \AdaptNote \sidenote {oo+m} [\@mpfn] { - % re-set basics: - \cs_set_eq:NN \footnote \footnotedefault - \cs_set_eq:NN \footnotemark \footnotemarkdefault - \cs_set_eq:NN \multfootnote \multfootnotedefault + \IfNoValueTF {#1} + {#NOTE{#3}} + { \IfNoValueTF {#2} {#NOTE[#1]{#3}} {#NOTE[#1][#2]{#3}} } } } - %% the `fixfoot' package: - \fnpct_treatment:nn {fixfoot} + } + %% endnotes: + \fnpct_treatment:nn {endnotes} + { + \AdaptNote \endnote {o+m} + { \IfNoValueTF {#1} {#NOTE{#2}} {#NOTE[#1]{#2}} } + \AdaptNote \endnotemark {o} [endnote] + { \IfNoValueTF {#1} {#NOTE} {#NOTE[#1]} } + \fnpct_if_multiple:T { \MultVariant \endnote } + } + % enotez: + \fnpct_treatment:nn {enotez} + { + \AdaptNote \endnote {o+m} { \IfNoValueTF {#1} {#NOTE{#2}} {#NOTE[#1]{#2}} } + \AdaptNote \endnotemark {o} [endnote] { \IfNoValueTF {#1} {#NOTE} {#NOTE{#1}} } + \fnpct_if_multiple:T { \MultVariant \endnote } + \hook_gput_code:nnn {fnpct/rangesetup} {enotez} { - \prop_map_inline:Nn \l__fnpct_footnote_fixfoot_prop - { \fnpct_renew_no_arg:cc {#2} {fnpct_orig_fix_#2:w} } + \fnpct_if_current:NT \endnote + { \int_gincr:N \g__enotez_endnote_id_int } } - %% the `sepfootnotes' package: - \fnpct_treatment:nn {sepfootnotes} + } + %% manyfoot/bigfoot + \fnpct_treatment:nn {manyfoot} + { + \__fnpct_get_fnclasses:NN \MFL@list \l__fnpct_footnote_class_seq + \seq_map_inline:Nn \l__fnpct_footnote_class_seq { - \prop_map_inline:Nn \l__fnpct_sepfootnote_foot_classes_prop + \str_if_eq:nnTF {#1} {default} { - \fnpct_renew_and_mult_no_opt:ccc {#2note} - {fnpct_orig_sep_#2:w} {#2multnote} - \fnpct_renew_and_mult_no_opt:ccc {#2quicknote} - {fnpct_orig_sep_#2_quick:w} {#2multquicknote} - \fnpct_renew_no_opt:cc {#2notemark} {fnpct_orig_sep_#2_mark:w} + \cs_if_exist:NT \footnotedefault + { + \AdaptNoteName {footnote#1} {o+m} + { \IfNoValueTF {##1} {##NOTE{##2}} {##NOTE[##1]{##2}} } + \AdaptNoteName {footnotemark#1} {o} [footnote#1] + { \IfNoValueTF {##1} {##NOTE} {##NOTE[##1]} } + \fnpct_if_multiple:T { \MultVariantName {footnote#1} } + } } - \prop_map_inline:Nn \l__fnpct_sepfootnote_end_classes_prop { - \fnpct_renew_and_mult_no_opt:ccc {#2note} - {fnpct_orig_sep_#2:w} {#2multnote} - \fnpct_renew_no_opt:cc {#2notemark} {fnpct_orig_sep_#2_mark:w} + \AdaptNoteName {footnote#1} {o+m} + { \IfNoValueTF {##1} {##NOTE{##2}} {##NOTE[##1]{##2}} } + \AdaptNoteName {footnotemark#1} {o} [footnote#1] + { \IfNoValueTF {##1} {##NOTE} {##NOTE[##1]} } + \fnpct_if_multiple:T { \MultVariantName {footnote#1} } } } } - } - -% `bigfoot' package -% \fnpct_special_treatment:nn {fixfoot} -% { -% \bool_if:NT \l__fnpct_bigfoot_default_top_bool -% { \DeclareNewFootnote {default} } -% } - -% `fixfoot' package -\fnpct_special_treatment:nn {fixfoot} - { - % hook into \DeclareFixedFootnote so we can redefine all footnote - % classes defined be users - \cs_new_eq:NN \fnpct_new_fixnote:w \DeclareFixedFootnote - \RenewDocumentCommand \DeclareFixedFootnote {smm} + %% fixfoot + \fnpct_treatment:nn {fixfoot} { - \prop_put:Nnx \l__fnpct_footnote_fixfoot_prop {#2} - { \cs_to_str:N #2 } - \IfBooleanTF {#1} - { \fnpct_new_fixnote:w * {#2} {#3} } - { \fnpct_new_fixnote:w {#2} {#3} } + \fnpct_if_ranges:TF + { + \msg_warning:nnnn {fnpct} {cannot-adapt-with-ranges} + {fixfoot} + { + There~ cannot~ be~ suitable~ \..text~ versions~ for~ the~ + fixed~ notes. + } + } + { + \seq_map_inline:Nn \l__fnpct_footnote_fixfoot_seq + { \AdaptNote #1 {} { ##NOTE } } + } } - } - -% `pagenote' package: -\fnpct_special_treatment:nn {pagenote} - { - \tl_put_left:Nn \makepagenote - { \bool_set_true:N \l__fnpct_makepagenote_bool } - } - -% `sepfootnotes' package: -\fnpct_special_treatment:nn {sepfootnotes} - { - \cs_new_eq:NN \fnpct_orig_new_footnotes:w \newfootnotes - \cs_new_eq:NN \fnpct_orig_new_endnotes:n \newendnotes - \cs_new_eq:NN \fnpct_orig_new_symbolnotes:w \newsymbolfootnotes - \RenewDocumentCommand \newfootnotes {sm} + %% pagenote + \fnpct_treatment:nn {pagenote} { - \prop_put:Nnn \l__fnpct_sepfootnote_foot_classes_prop {#2} {#2} - \IfBooleanTF {#1} - { \fnpct_orig_new_footnotes:w * {#2} } - { \fnpct_orig_new_footnotes:w {#2} } + \fnpct_if_ranges:TF + { + \msg_warning:nnnn {fnpct} {cannot-adapt-with-ranges} + {pagenote} + { + The~ command~ \pagenote~ misses~ a~ suitable~ \pagenotetext~ + version. + } + } + { + \bool_if:NTF \l__fnpct_makepagenote_bool + { + \AdaptNote \pagenote {o+m} + { \IfNoValueTF {#1} {#NOTE{#2}} {#NOTE[#1]{#2}} } + \fnpct_if_multiple:T { \MultVariant \pagenote } + } + { \msg_warning:nn {fnpct} {pagenote} } + } } - \RenewDocumentCommand \newendnotes {m} + %% parnotes + \fnpct_treatment:nn {parnotes} { - \prop_put:Nnn \l__fnpct_sepfootnote_end_classes_prop {#1} {#1} - \fnpct_orig_new_endnotes:n {#1} + \fnpct_if_ranges:TF + { + \msg_warning:nnnn {fnpct} {cannot-adapt-with-ranges} + {parnotes} + { + The~ command~ \parnote~ misses~ a~ suitable~ \parnotetext~ + version. + } + } + { + \AdaptNote \parnote {o+m} + { \IfNoValueTF {#1} {#NOTE{#2}} {#NOTE[#1]{#2}} } + \fnpct_if_multiple:T { \MultVariant \parnote } + } } - \RenewDocumentCommand \newsymbolfootnotes {om} + %% tablefootnote + \fnpct_treatment:nn {tablefootnote} { - \prop_put:Nnn \l__fnpct_sepfootnote_symbol_classes_prop {#2} {#2} - \IfNoValueTF {#1} - { \fnpct_orig_new_symbolnotes:w {#2} } - { \fnpct_orig_new_symbolnotes:w [#1] {#2} } + \fnpct_if_ranges:TF + { + \msg_warning:nnnn {fnpct} {cannot-adapt-with-ranges} + {tablefootnote} + { + The~ command~ \tablefootnote~ misses~ a~ suitable~ + \tablefootnotetext~ version. + } + } + { + \AdaptNote \tablefootnote {o+m} [footnote] + { \IfNoValueTF {#1} {#NOTE{#2}} {#NOTE[#1]{#2}} } + } } - } - -% -------------------------------------------------------------------------- -\RequirePackage{translations} -\AtBeginDocument{ - \ifcurrentbaselanguage{French} + %% sepfootnotes + \fnpct_treatment:nn {sepfootnotes} { - \AfterBeginDocument{ - \cs_if_exist:NT \@footnotemarkORI + \cs_set:Nn \__fnpct_sep_mark:n {\footnotemark} + \seq_map_inline:Nn \l__fnpct_sepfootnotes_seq { - \let\@footnotemark\@footnotemarkORI - \setfnpct{ - before-footnote-space = - \l__fnpct_french_before_footnote_space_dim - } + \cs_if_eq:cNTF {#1notemark} \__fnpct_sep_mark:n + {% defined with \newfootnotes + \AdaptNoteName {#1note} {m} [\@mpfn] {##NOTE{##1}} + } + {% defined with \newfootnotes* or \newendnotes + \AdaptNoteName {#1note} {m} {##NOTE{##1}} + \hook_gput_code:nnn {fnpct/rangesetup} {sepfootnotes} + { + \fnpct_if_current:cT {#1note} + { + \addtocounter {#1note} {-1} + \sep@refstepcounter {#1note} + } + } + } + \AdaptNoteName {#1notemark} {m} {##NOTE{##1}} + \AdaptNoteName {#1quicknote} {m} {##NOTE{##1}} + \fnpct_if_multiple:T { \MultVariantName {#1note} } + \fnpct_if_multiple:T { \MultVariantName {#1quicknote} } } } - }{} -} + } +\file_input_stop: % -------------------------------------------------------------------------- -% SETUP COMMAND: -\NewDocumentCommand \setfnpct {m} - { \keys_set:nn {fnpct} {#1} } - -\file_input_stop: +% OTHER PACKAGES: +# should just work: +footnpag +ednotes +yafoot + +# cannot be adapted for the time being: +sidenotes + +# works: +endnotes +snotez +footmisc +footnote (not the environment) +manyfoot +bigfoot +enotez +sepfootnotes + +# works, but not with ranges: +fixfoot +pagenote +parnotes +tablefootnote % -------------------------------------------------------------------------- % HISTORY: -2012/05/18 v0.1alpha - various changes still possible without announcement - until declared `v0.1' -2012/05/19 v0.1beta - considered ready for public use, needs feedback, though -2012/05/20 v0.1beta-a - minor changes -2012/05/20 v0.1beta-b - added `pagenote' support - - added `tablefootnote' support -2012/05/20 v0.1beta-c - optional star argument to \multfootnote that only invokes - \footnotetext - - option `dont-mess-around': disable switching and kerning -2012/05/21 v0.1beta-d - \innernote for nesting - - `hyperref' support - - bugfix in \multfootnote -2012/05/21 v0.1beta-e - `sepfootnotes' support -2012/05/22 v0.1beta-f - reorganized code -2012/05/22 v0.1 - a bit more cleaning up of the code - - completed documentation - - ready for CTAN +2012/05/22 v0.1 - ready for CTAN 2012/05/23 v0.1a - \AdaptNoteNoMult, \AdaptNoteOpt, \AdaptNoteOptNoMult - support `sidenotes' package - better support for citing commands @@ -1212,9 +1393,11 @@ 2019/10/05 v0.5 - fix issue 18 - remove option `bigfoot-default-top' - support `manyfoot' package - -% -------------------------------------------------------------------------- -% NOTES: -- `footnote' package => not compatible -- `ednotes' package => not tested; who knows? -- `sidenotes' package => mot easily patchable, see pull request #1 +2020/01/12 v0.5a - support `snotez' with `dblrg=false' +2021/01/21 v1.0 - new implementation: + * support footnote ranges when possible + * support more packages + * more flexible way to adapt unknown note commands + with less commands + * drop support of \innernote (maybe re-implement it in + future versions, depending on user feedback) |