% -------------------------------------------------------------------------- % the FNPCT package % % footnote kerning % % -------------------------------------------------------------------------- % Clemens Niederberger % Web: https://github.com/cgnieder/fnpct/ % E-Mail: contact@mychemistry.eu % -------------------------------------------------------------------------- % Copyright 2012--2020 Clemens Niederberger % % This work may be distributed and/or modified under the % conditions of the LaTeX Project Public License, either version 1.3 % 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. % % 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} \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} \tl_const:Nn \c_fnpct_version_subrelease_tl {} \tl_const:Nx \c_fnpct_version_number_tl { \c_fnpct_version_major_number_tl . \c_fnpct_version_minor_number_tl } \tl_const:Nx \c_fnpct_version_tl { \c_fnpct_version_number_tl \c_fnpct_version_subrelease_tl } \tl_const:Nn \c_fnpct_info_tl {footnote~ kerning} \ProvidesExplPackage {fnpct} {\c_fnpct_date_tl} {\c_fnpct_version_tl} {\c_fnpct_info_tl} % -------------------------------------------------------------------------- % this is plain's \nobreak: \cs_new:Npn \fnpct_no_break: { \tex_penalty:D 10000 \scan_stop: } % -------------------------------------------------------------------------- % variables: \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 \int_new:N \l__fnpct_tmpa_int \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 \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 \seq_new:N \l__fnpct_footnote_class_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 % -------------------------------------------------------------------------- % 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 {Nx,Nxo} \cs_generate_variant:Nn \prop_put:Nnn {Nnx} \cs_generate_variant:Nn \prop_if_in:NnTF {Nx} % -------------------------------------------------------------------------- % messages: \cs_new_protected:Npn \fnpct_dont_mess_around: { \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 { ................................................. } } \msg_new:nnn {fnpct} {already-adapted} { The~ command~ \token_to_str:N #1 \c_space_tl has~ already~ been~ adapted. \\ I~ will~ do~ nothing~ instead. } \msg_new:nnn {fnpct} {pagenote} { If~ you~ use~ the~ `pagenote'~ package~ with~ `fnpct'~ please~ make~ sure~ to~ use~ \token_to_str:N \makepagenote \c_space_tl after~ loading~ `fnpct'! } \msg_new:nnn {fnpct} {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. } \cs_new_protected:Npn \fnpct_message:nx #1#2 { \bool_if:NTF \l__fnpct_strict_bool { \msg_error:nnx {fnpct} {#1} } { \msg_warning:nnx {fnpct} {#1} } {#2} } % -------------------------------------------------------------------------- \prg_new_conditional:Npnn \fnpct_if_package_loaded:n #1 {p,T,F,TF} { \@ifpackageloaded {#1} { \prg_return_true: } { \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 {,} } % -------------------------------------------------------------------------- % #1: before/after % #2: punctuation mark % #3: dimension \cs_new_protected:Npn \fnpct_set_punctuation_dim:nnn #1#2#3 { \prop_put:cnx { l__fnpct_punctuation_marks_#1_prop } {#2} { \dim_eval:n {#3} } } \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 } \cs_new_protected:Npn \fnpct_rm_punctuation: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} } \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} \cs_new_protected:Npn \__fnpct_add_punctuation:w #1[#2]#3 \q_stop { \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} } } { \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} } { % #2 is a first option (= after space), #1 might be more than one token: \tl_if_single_token:nTF {#1} { \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 } } } } % 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 } } } % -------------------------------------------------------------------------- % options: \keys_define:nn {fnpct} { 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} % -------------------------------------------------------------------------- % MAIN INTERNAL FOOTNOTE FUNCTION: % write the notes: \cs_new:Npn \__fnpct_no_value_or_quark_no_value:nTF #1#2#3 { \IfNoValueTF {#1} {#2} { \quark_if_no_value:nTF {#1} {#2} {#3} } } \cs_new:Npn \fnpct_write_note:Nnnn #1#2#3#4 { \__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} } } } \cs_new:Npn \fnpct_write_snote:Nnnn #1#2#3#4 { \__fnpct_no_value_or_quark_no_value:nTF {#2} { \__fnpct_no_value_or_quark_no_value:nTF {#3} { #1 {#4} } { #1 [#3] {#4} } } { \__fnpct_no_value_or_quark_no_value:nTF {#3} { #1 (#2) {#4} } { #1 (#2) [#3] {#4} } } } % check for punctuation: \cs_new_protected:Npn \fnpct_check_punctuation:TF #1#2 { \__fnpct_check_punctuation:nTF {0} {#1} {#2} } \cs_new_protected:Npn \__fnpct_check_punctuation:nTF #1#2#3 { \__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} } } \cs_new_protected:Npn \__fnpct_check_punctuation_aux:nnn #1#2#3 { \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} } \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 { \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: } \cs_new_protected:Npn \__fnpct_check_multiple: { \prop_map_inline:Nn \g__fnpct_adapted_notes_prop { \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_set_true:N \l__fnpct_multiple_footnotes_bool \prop_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 } } { \prg_return_true: } { \prg_return_false: } } % this is where the magic happens: \cs_new_protected:Npn \fnpct_handle_punctuation:n #1 { \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 } { % 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 } } { % else insert space and then note \bool_if:NTF \l__fnpct_multiple_footnotes_bool { \bool_set_false: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 \bool_set_false:N \l__fnpct_reverse_switch_bool } } } % #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 { % if a punctuation mark follows remove it, insert dot, skip back % and then insert footnote \bool_if:NF \l__fnpct_dont_mess_around_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 } } \cs_generate_variant:Nn \fnpct_handle_note:Nnnnn {c} \cs_new_protected:Npn \fnpct_handle_snote:Nnnnn #1#2#3#4#5 { \bool_if:NF \l__fnpct_dont_mess_around_bool { \IfBooleanT {#5} { \bool_set_true:N \l__fnpct_reverse_switch_bool } } \fnpct_handle_punctuation:n { \fnpct_write_snote:Nnnn #1 {#2} {#3} {#4} \fnpct_write_inner:N #1 } } \cs_generate_variant:Nn \fnpct_handle_snote:Nnnnn {c} % -------------------------------------------------------------------------- % 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 { \bool_if:NF \l__fnpct_dont_mess_around_bool { \IfBooleanT {#2} { \bool_set_true:N \l__fnpct_reverse_switch_bool } } % 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 } } \cs_generate_variant:Nn \fnpct_mult_note:Nnn {c} % #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 } } % 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 } { \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 } } } \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} } } { \fnpct_write_note:Nnnn #5 {#2} {#3} {#4} } \fnpct_write_inner:N #5 } % -------------------------------------------------------------------------- % 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} { \IfNoValueTF {#1} { % 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 { \prop_gput:Nxo \g__fnpct_inner_footnote_hyperref_prop { \thefootnote } { \Hy@footnote@currentHref } } } { \fnpct_orig_footnotemark:w [#1] \prop_gput:Nnn \g__fnpct_inner_footnote_prop {#1} {#2} \bool_if:NT \l__fnpct_hyperref_bool { \prop_gput:Nno \g__fnpct_inner_footnote_hyperref_prop {#1} { \Hy@footnote@currentHref } } } } \cs_new_protected:Npn \fnpct_write_inner:N #1 { \token_if_eq_meaning:NNF #1 \fnpct_inner_footnote:w { \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 } } \NewDocumentCommand \writeinnernotes {} { \fnpct_write_inner:N X } % -------------------------------------------------------------------------- % MANUAL KERNING: \cs_new_protected:Npn \fnpct_kfp: { \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 } } \cs_new_protected:Npn \fnpct_kfc: { \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 } } \NewDocumentCommand \kfp {} { \fnpct_kfp: } \NewDocumentCommand \kfc {} { \fnpct_kfc: } % -------------------------------------------------------------------------- % NORMAL MARKS: \AtBeginDocument { \bool_if:NT \l__fnpct_normal_marks_bool { \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 } } } % -------------------------------------------------------------------------- % LET'S MAKE IT EASIER TO ADAPT EXISTING FUNCTIONS: % COPY, RENEW AND CREATE MULT \prg_new_conditional:Npnn \fnpct_if_adapted:N #1 {p,T,F,TF} { \prop_if_in:NnTF \g__fnpct_adapted_notes_prop {#1} { \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} } % standard \footnote[]{} like commands % #1: old new name % #2: internal name of old definition % #3: mult-variant % % \footnote[]{} like: \cs_new_protected:Npn \fnpct_renew_and_mult: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 {so+m} { \fnpct_handle_note:Nnnnn #2 {##2} { \q_no_value } {##3} {##1} } } } } \cs_generate_variant:Nn \fnpct_renew_and_mult:NNN {ccc,Nc} % \footnote{} 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} { \fnpct_handle_note:Nnnnn #2 { \q_no_value } { \q_no_value } {##2} {##1} } } } } \cs_generate_variant:Nn \fnpct_renew_and_mult_no_opt:NNN {Nc,ccc} % renew but don't create mult-variant: % \footnote[]{} like: \cs_new_protected:Npn \fnpct_renew:NN #1#2 { \fnpct_if_adapted:NF #1 { \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} } } } \cs_generate_variant:Nn \fnpct_renew:NN {cc,Nc} % new \cs_new_protected:Npn \fnpct_new:NN #1#2 { \fnpct_if_adapted:NF #1 { \fnpct_add_to_adapted:NN #1#2 \NewDocumentCommand #1 {so+m} { \fnpct_handle_note:Nnnnn #2 {##2} { \q_no_value } {##3} {##1} } } } \cs_generate_variant:Nn \fnpct_new:NN {cc,Nc} % \note[][]{} like: \cs_new_protected:Npn \fnpct_renew_and_mult_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 {soo+m} { \fnpct_handle_note:Nnnnn #2 {##2} {##3} {##4} {##1} } } } } \cs_generate_variant:Nn \fnpct_renew_and_mult_opt:NNN {ccc,Nc} % \note()[]{} like: \cs_new_protected:Npn \fnpct_renew_and_mult_snotez: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 {sd()o+m} { \fnpct_handle_snote:Nnnnn #2 {##2} {##3} {##4} {##1} } } } } \cs_generate_variant:Nn \fnpct_renew_and_mult_snotez:NNN {ccc,Nc} \cs_new_protected:Npn \fnpct_renew_opt:NN #1#2 { \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} } } } \cs_generate_variant:Nn \fnpct_renew_opt:NN {cc,Nc} % \note{} like \cs_new_protected:Npn \fnpct_renew_no_opt:NN #1#2 { \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} } } } \cs_generate_variant:Nn \fnpct_renew_no_opt:NN {cc,Nc} % \note like \cs_new_protected:Npn \fnpct_renew_no_arg:NN #1#2 { \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} } } } \cs_generate_variant:Nn \fnpct_renew_no_arg:NN {cc} % create mult-variant \cs_new_protected:Npn \fnpct_create_mult_variant:NN #1#2 { \NewDocumentCommand #1 {s+m} { \fnpct_mult_note:Nnn #2 {##1} {##2} } } % \footnotemark[] like commands: \cs_new_protected:Npn \fnpct_renew_mark:NN #1#2 { \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} } } } \cs_generate_variant:Nn \fnpct_renew_mark:NN {cc,Nc} % user commands: \NewDocumentCommand \AdaptNote {mm} { \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 } } \NewDocumentCommand \AdaptNoteNoMult {m} { \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 } } } \NewDocumentCommand \AdaptNoteOpt {mm} { \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 } } \NewDocumentCommand \AdaptSnotez {mm} { \cs_if_exist:cTF { fnpct_orig_ \cs_to_str:N #1 :w } { \fnpct_message:nx {already-adapted} {#1} } { \fnpct_renew_and_mult_snotez:NcN #1 { fnpct_orig_ \cs_to_str:N #1 :w } #2 } } \NewDocumentCommand \AdaptNoteOptNoMult {m} { \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 } } } \NewDocumentCommand \AdaptNoteNoOpt {mm} { \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 } } \NewDocumentCommand \AdaptNoteNoOptNoMult {m} { \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 } } } \NewDocumentCommand \AdaptNoteMark {m} { \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 } } } % -------------------------------------------------------------------------- % 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 {~} \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 \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_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 { \fnpct_if_package_loaded:nTF {hyperref} { \bool_set_true:N \l__fnpct_hyperref_bool } { \cs_if_exist:NF \AfterBeginDocument { \cs_new:Npn \AfterBeginDocument #1 {#1} } } \AfterBeginDocument { \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} { \AdaptNote \endnote \multendnote \AdaptNoteMark \endnotemark } %% the `enotez' package: \fnpct_treatment:nn {enotez} { \AdaptNote \endnote \multendnote } %% the `snotez' package: \fnpct_treatment:nn {snotez} { \legacy_if:nTF {snotez@dblarg} { \AdaptNoteOpt \sidenote \multsidenote } { \AdaptSnotez \sidenote \multsidenote } \AdaptNoteMark \sidenotemark } %% the `parnotes' package: \fnpct_treatment:nn {parnotes} { \AdaptNote \parnote \multparnote } %% the `pagenote' package: \fnpct_treatment:nn {pagenote} { \bool_if:NTF \l__fnpct_makepagenote_bool { \AdaptNote \pagenote \multpagenote } { \msg_warning:nn {fnpct} {pagenote} } } %% the `tablefootnote' package: \fnpct_treatment:nn {tablefootnote} { \AdaptNote \tablefootnote \multtablefootnote } %% the `manyfoot' package (also loaded by `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 { \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 `bigfoot' package: \fnpct_special_treatment:nn {bigfoot} { \cs_if_exist:NT \footnotedefault { % re-set basics: \cs_set_eq:NN \footnote \footnotedefault \cs_set_eq:NN \footnotemark \footnotemarkdefault \cs_set_eq:NN \multfootnote \multfootnotedefault } } %% the `fixfoot' package: \fnpct_treatment:nn {fixfoot} { \prop_map_inline:Nn \l__fnpct_footnote_fixfoot_prop { \fnpct_renew_no_arg:cc {#2} {fnpct_orig_fix_#2:w} } } %% the `sepfootnotes' package: \fnpct_treatment:nn {sepfootnotes} { \prop_map_inline:Nn \l__fnpct_sepfootnote_foot_classes_prop { \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} } \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} } } } } % `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} { \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} } } } % `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} { \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} } } \RenewDocumentCommand \newendnotes {m} { \prop_put:Nnn \l__fnpct_sepfootnote_end_classes_prop {#1} {#1} \fnpct_orig_new_endnotes:n {#1} } \RenewDocumentCommand \newsymbolfootnotes {om} { \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} } } } % -------------------------------------------------------------------------- \RequirePackage{translations} \AtBeginDocument{ \ifcurrentbaselanguage{French} { \AfterBeginDocument{ \cs_if_exist:NT \@footnotemarkORI { \let\@footnotemark\@footnotemarkORI \setfnpct{ before-footnote-space = \l__fnpct_french_before_footnote_space_dim } } } }{} } % -------------------------------------------------------------------------- % SETUP COMMAND: \NewDocumentCommand \setfnpct {m} { \keys_set:nn {fnpct} {#1} } \file_input_stop: