% -------------------------------------------------------------------------- % the FNPCT package % % footnotes' interaction with punctuation % % -------------------------------------------------------------------------- % Clemens Niederberger % Web: https://github.com/cgnieder/fnpct/ % E-Mail: clemens@cnltx.de % -------------------------------------------------------------------------- % Copyright 2012--2022 Clemens Niederberger % % This work may be distributed and/or modified under the % 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.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. % -------------------------------------------------------------------------- \RequirePackage {l3keys2e} \ExplSyntaxOn \DeclareRelease {v0} {2019-10-05} {fnpct-2019-10-05.sty} \DeclareHookRule {begindocument} {fnpct} {after} {hyperref} \tl_const:Nn \c_fnpct_date_tl {2022/02/27} \tl_const:Nn \c_fnpct_version_major_number_tl {1} \tl_const:Nn \c_fnpct_version_minor_number_tl {1} \tl_const:Nn \c_fnpct_version_subrelease_tl {a} \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 {footnotes'~ interaction~ with~ punctuation} \ProvidesExplPackage {fnpct} {\c_fnpct_date_tl} {\c_fnpct_version_tl} {\c_fnpct_info_tl} \DeclareCurrentRelease {v1} {\c_fnpct_date_tl} % -------------------------------------------------------------------------- % scratch variables and variants of kernel functions: \tl_new:N \l__fnpct_tmpa_tl \seq_new:N \l__fnpct_tmpa_seq \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} \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_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 \bool_new:N \l__fnpct_unspace_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_new:N \l__fnpct_mult_variant_prefix_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 \int_new:N \l__fnpct_collection_int \dim_new:N \l__fnpct_before_footnote_dim % -------------------------------------------------------------------------- % messages: \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-load-time-option} { Unknown~ option~ `#1'! \\ I~ don't~ know~ the~ option~ `#1'.~ Please~ make~ sure~ there~ is~ no~ typo.~ Check~ the~ manual~ for~ help.~ Did~ you~ mean~ to~ use~ it~ in~ \token_to_str:N \setfnpct ? } \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} { 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} {ranges-hyperref} { 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~ to~ use~ \token_to_str:N \makepagenote \c_space_tl after~ loading~ `fnpct'! } \msg_new:nnn {fnpct} {option-deprecated} { The~ option~ `#1'~ is~ deprecated \tl_if_blank:nF {#2} { .~ Please~ use~ option~ `#2'~ instead } \c_space_tl \msg_line_context: . } \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/load-time} { 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-load-time-option} } \ProcessKeysPackageOptions {fnpct/load-time} \keys_define:nn {fnpct/load-time} { 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: } } % -------------------------------------------------------------------------- \prg_new_conditional:Npnn \fnpct_if_package_loaded:n #1 {p,T,F,TF} { \@ifpackageloaded {#1} { \prg_return_true: } { \prg_return_false: } } \prg_new_conditional:Npnn \fnpct_if_class_loaded:n #1 {p,T,F,TF} { \@ifclassloaded {#1} { \prg_return_true: } { \prg_return_false: } } % -------------------------------------------------------------------------- % #1: cs \prg_new_conditional:Npnn \fnpct_if_adapted:N #1 {T,F,TF} { \seq_if_in:NnTF \l__fnpct_adapted_commands_seq {#1} { \prg_return_true: } { \prg_return_false: } } \prg_generate_conditional_variant:Nnn \fnpct_if_adapted:N {c} {T,F,TF} % -------------------------------------------------------------------------- \cs_new_protected:Npn \fnpct_nobreak: { \tex_penalty:D 10000 \scan_stop: } \cs_new_protected:Npn \fnpct_skip_nobreak:N #1 { \fnpct_nobreak: \skip_horizontal:N #1 \fnpct_nobreak: } \cs_generate_variant:Nn \fnpct_skip_nobreak:N {c} % -------------------------------------------------------------------------- % 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} } \prg_new_conditional:Npnn \fnpct_class_if_exist:n #1 {p,T,F,TF} { \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} { \seq_if_in:NnTF \g__fnpct_actions_seq {#1} { \keys_set:nn {fnpct} { before-#1-space = #3 , after-#1-space = #4 } } { \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} } } \prg_new_conditional:Npnn \fnpct_action_if_exist:n #1 {p,T,F,TF} { \seq_if_in:NnTF \g__fnpct_actions_seq {#1} { \prg_return_true: } { \prg_return_false: } } % 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 { \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} } % #1: class % #2: code where `#1' refers to the action name \cs_new:Npn \fnpct_foreach_action:nn #1#2 { \fnpct_class_if_exist:nT {#1} { \seq_map_inline:cn {g__fnpct_class_#1_seq} {#2} } } \cs_new_eq:NN \fnpct_action_break: \seq_map_break: % #1: token \cs_new_protected:Npn \fnpct_remove_trailing_token:N #1 { \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_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 { \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 } % deactivate a token: \cs_new_protected:Npn \fnpct_deactivate_trailing_token:n #1 { \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 } % #1: tokenlist \prg_new_protected_conditional:Npnn \fnpct_if_trailing_tokens:n #1 {T,F,TF} { \bool_set_false:N \l__fnpct_trailing_tokens_bool \tl_map_inline:nn {#1} { \bool_if:cT {l__fnpct_trailing_##1_bool} { \bool_set_true:N \l__fnpct_trailing_tokens_bool \tl_map_break: } } \bool_if:NTF \l__fnpct_trailing_tokens_bool { \prg_return_true: } { \prg_return_false: } } % -------------------------------------------------------------------------- % #1: token \prg_new_protected_conditional:Npnn \__fnpct_check_trail:N #1 {T,F,TF} { \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: } { \tl_if_empty:NTF \l__fnpct_trailing_tokens_tl { \prg_return_false: } { \tl_map_inline:Nn \l__fnpct_trailing_tokens_tl { \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: } } \bool_if:NTF \l_fnpct_trailing_action_bool { \prg_return_true: } { \prg_return_false: } } } } % #1: class name \prg_new_protected_conditional:Npnn \fnpct_if_class:n #1 {T,F,TF} { \bool_if:NTF \l_fnpct_trailing_action_bool { \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: } } % #1: action name \prg_new_protected_conditional:Npnn \fnpct_if_action:n #1 {T,F,TF} { \bool_if:NTF \l_fnpct_trailing_action_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: } } { \prg_return_false: } } % -------------------------------------------------------------------------- % 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 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 { \cs_undefine:c {fnpct_original_ \__fnpct_remove_backslash:N #1 :w} \exp_args:Nc \DeclareCommandCopy { fnpct_original_ \__fnpct_remove_backslash:N #1 :w } #1 \seq_put_right:Nn \l__fnpct_adapted_commands_seq {#1} \fnpct_set_counter_name:Nx #1 { \__fnpct_remove_backslash:N #1 } } \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 { \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} { \fnpct_inside_range:TF { \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_swap:nn { \fnpct_before: \fnpct_print_collection: \fnpct_print_note:w #1 \fnpct_after: } {#2} } { \__fnpct_swap:nn {#1} {#2} } } \cs_new_protected:Npn \__fnpct_swap:nn #1#2 { \fnpct_if_switched:TF { \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} } } \cs_new:Npn \fnpct_print_note:w \fnpct_before: #1 \fnpct_after: { \exp_not:n { #1 } } % multiple footnotes and ranges: \cs_new_protected:Npn \__fnpct_collect:n #1 { \int_incr:N \l__fnpct_collection_int \seq_put_right:Nx \l__fnpct_collection_seq { \fnpct_print_note:w #1 } } % #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_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 } \cs_new_protected:Npn \fnpct_print_collection: { \bool_set_false:N \l__fnpct_collection_bool \bool_set_true:N \l__fnpct_end_collection_bool % DEBUG: \fnpct_if_ranges:TF { \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 } } % -------------------------------------------------------------------------- % build up the frame for the adapted note commands: \prg_new_conditional:Npnn \fnpct_if_switched: {p,T,F,TF} { \bool_if:NTF \l__fnpct_switched_bool { \prg_return_true: } { \prg_return_false: } } \cs_new_protected:Npn \__fnpct_execute: {} \hook_gput_code:nnn {begindocument} {fnpct} { \bool_lazy_or:nnTF { \fnpct_if_package_loaded_p:n {biblatex} } { \fnpct_if_package_loaded_p:n {csquotes} } { \cs_new_protected:Npn \fnpct_unspace: { \bool_if:NT \l__fnpct_unspace_bool { \unspace } } } { \cs_new_protected:Npn \fnpct_unspace: { \bool_if:NT \l__fnpct_unspace_bool { \mode_if_horizontal:T { \dim_compare:nNnTF {\lastskip} > {0pt} { \tex_unskip:D \fnpct_unspace: } { \int_compare:nNnT {\lastpenalty} > {0} { \tex_unpenalty:D \fnpct_unspace: } } } } } } } % #1: boolean \cs_new_protected:Npn \fnpct_begin: { \fnpct_unspace: \__fnpct_check_after_end:w } % #1: code \cs_new_protected:Npn \__fnpct_check_after_end:w #1 \fnpct_end: { \cs_set_protected:Npn \__fnpct_execute: { \__fnpct_check_trail:NTF \l_peek_token { \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} } { % no trailing punctuation \bool_lazy_or:nnT { \fnpct_if_collection_p: } { \fnpct_if_switched_p: } { \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_new_protected:Npn \fnpct_end: { } \cs_new_protected:Npn \fnpct_before: { \bool_if:NF \l__fnpct_dont_mess_around_bool { \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_new_protected:Npn \fnpct_add_punctuation_space:n #1 { \fnpct_if_class:nT {punctuation} { \fnpct_foreach_action:nn {punctuation} { \fnpct_if_action:nT {##1} { \fnpct_skip_nobreak:c {l__fnpct_#1_##1_dim} \fnpct_action_break: } } } } \cs_new_protected:Npn \fnpct_after: { \bool_if:NF \l__fnpct_dont_mess_around_bool { \fnpct_if_switched:T { \fnpct_if_class:nT {punctuation} { \bool_set_false:N \l__fnpct_collection_bool } \bool_set_false:N \l__fnpct_end_collection_bool \bool_set_false:N \l__fnpct_switched_bool } } } % #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_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_adapt_note:Nnn {c} \cs_new_protected:Npn \fnpct_reverse:n #1 { \bool_if:NTF \l__fnpct_reverse_bool { \bool_if:nF } { \bool_if:nT } {#1} { \bool_set_true:N \l__fnpct_switched_bool } } % #1: code \cs_new_protected:Npn \fnpct_start:w #1 \fnpct_stop: { \fnpct_begin: \fnpct_before: \group_begin: #1 \group_end: \fnpct_after: \fnpct_end: } \cs_new_protected:Npn \fnpct_text: { \bool_set_false:N \l__fnpct_inside_range_bool \bool_gset_true:N \g__fnpct_text_bool } % -------------------------------------------------------------------------- % #1: note command % #2: arguments % #3: counter name % #4: code \NewDocumentCommand \AdaptNote {mmom} { \fnpct_adapt_note:Nnn #1 {#2} {#4} \IfNoValueF {#3} { \fnpct_set_counter_name:Nn #1 {#3} } } \NewDocumentCommand \AdaptNoteName {mmom} { \fnpct_adapt_note:cnn {#1} {#2} {#4} \IfNoValueF {#3} { \fnpct_set_counter_name:cn {#1} {#3} } } \NewDocumentCommand \AdaptText {mmm} { \fnpct_adapt_note:Nnn #1 {#2} { \fnpct_text: #3 } } \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} { 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 , unspace .bool_set:N = \l__fnpct_unspace_bool , unspace .initial:n = true , mult-fn-delim .tl_set:N = \l__fnpct_multiple_footnotes_delimiter_tl , mult-fn-delim .initial:n = {;} , mult-variant-prefix .tl_set:N = \l__fnpct_mult_variant_prefix_tl , mult-variant-prefix .initial:n = mult , 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 , punct-after .code:n = \fnpct_deprecate_option:n {reverse} , 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 } } } % deprecate options of earlier version unless it still exists: \clist_map_inline:nn { 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 \cs_new_protected:Npn \fnpct_create_mult_variant:N #1 { \exp_args:Nc \NewDocumentCommand { \l__fnpct_mult_variant_prefix_tl \__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} } % -------------------------------------------------------------------------- % TAKE CARE OF FRENCH SETTINGS \RequirePackage {translations} \hook_gput_code:nnn {begindocument/end} {fnpct} { \ifcurrentbaselanguage {French} { \cs_if_exist:NT \StandardFootnotes { \cs_set_eq:NN \@footnotemark \@footnotemarkORI \StandardFootnotes } \keys_set:nn {fnpct} { before-footnote-space = .16667em } } {} } % -------------------------------------------------------------------------- \hook_gput_code:nnn {begindocument} {fnpct} { \fnpct_if_class_loaded:nTF {memoir} { \renewcommand* } { \providecommand* } \multfootsep {,} \providecommand* \multfootrange {--} \tl_set:Nn \l__fnpct_range_tl { \textsuperscript { \multfootrange } } } % -------------------------------------------------------------------------- % DO THE REDEFINING: % % 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/#1/after} {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 \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_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 } % `fixfoot' package \fnpct_special_treatment:nn {fixfoot} { % 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} { \seq_put_right:Nn \l__fnpct_footnote_fixfoot_seq {#2} \IfBooleanTF {#1} { \fnpct_new_fixnote:w * {#2} {#3} } { \fnpct_new_fixnote:w {#2} {#3} } } } % `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 } } % `sepfootnotes' package: \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/end} {fnpct} { \fnpct_if_package_loaded:nT {hyperref} { \fnpct_if_ranges:T { \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} } } } } %% LaTeX's defaults: \fnpct_if_class_loaded:nTF {beamer} { \AdaptNote \footnote{d<>o+m} [\beamer@mpfn] { \IfNoValueTF{#1} {\IfNoValueTF{#2}{#NOTE{#3}}{#NOTE[#2]{#3}}} {\IfNoValueTF{#2}{#NOTE<#1>{#3}}{#NOTE<#1>[#2]{#3}}} } \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} } \AdaptNote \footref {m} { #NOTE{#1} } %% snotez: \fnpct_treatment:nn {snotez} { \AdaptNote \sidenote {d()oo+m} { \IfNoValueTF {#1} { \IfNoValueTF {#2} {#NOTE{#4}} { \IfNoValueTF {#3} {#NOTE[#2]{#4}} {#NOTE[#2][#3]{#4}} } } { \IfNoValueTF {#2} {#NOTE(#1){#4}} {#NOTE(#1)[#2]{#4}} } } \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} } %% tufte-latex: \bool_lazy_or:nnT { \fnpct_if_class_loaded_p:n {tufte-handout} } { \fnpct_if_class_loaded_p:n {tufte-book} } { \fnpct_if_ranges:TF { \msg_warning:nnnn {fnpct} {cannot-adapt-with-ranges} {tufte-latex} { The~ command~ \sidenote~ misses~ a~ suitable~ \sidenotetext~ version. } } { \AdaptNote \sidenote {oo+m} [\@mpfn] { \IfNoValueTF {#1} {#NOTE{#3}} { \IfNoValueTF {#2} {#NOTE[#1]{#3}} {#NOTE[#1][#2]{#3}} } } } } %% 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} { \fnpct_if_current:NT \endnote { \int_gincr:N \g__enotez_endnote_id_int } } } %% 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 { \str_if_eq:nnTF {#1} {default} { \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} } } } { \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} } } } } %% fixfoot \fnpct_treatment:nn {fixfoot} { \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 \fnpct_treatment:nn {pagenote} { \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} } } } %% parnotes \fnpct_treatment:nn {parnotes} { \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 } } } %% tablefootnote \fnpct_treatment:nn {tablefootnote} { \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}} } } } %% sepfootnotes \fnpct_treatment:nn {sepfootnotes} { \cs_set:Nn \__fnpct_sep_mark:n {\footnotemark} \AdaptNote \sepfootnote {m} [\@mpfn] {#NOTE{#1}} \seq_map_inline:Nn \l__fnpct_sepfootnotes_seq { \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: % -------------------------------------------------------------------------- % 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/22 v0.1 - ready for CTAN 2012/05/23 v0.1a - \AdaptNoteNoMult, \AdaptNoteOpt, \AdaptNoteOptNoMult - support `sidenotes' package - better support for citing commands - error checking in the \AdaptNote commands - package option `strict' 2012/05/26 v0.2 - added possibility to add punctuation marks to the switching/kerning mechansim (or remove them) 2012/06/01 v0.2a - * switches behaviour also with `punct-after=true' - `dont-mess-around' disables * 2012/06/07 v0.2b - bugfix: \kfp and \kfc now get the updated values if add-punctuation was added. They also won't allow line breaks any more 2012/06/28 v0.2c - bugfix: works now flawless together with `bigfoot' 2012/07/07 v0.2d - check for all sorts of following footnotes to insert \l__fnpct_multiple_footnote_separator_tl 2012/07/24 v0.2e - improved scanning ahead for punctuation marks, adapted to deprecated functions in l3kernel and l3packages 2012/08/27 v0.2f - switched to internal scratch variables 2012/11/14 v0.2g - adapt changes in `sidenotes' package 2013/01/18 v0.2h - bug fixed: \l__fnpct_multiple_footnote_separator_tl should be {,} when `memoir' is loaded 2013/01/21 v0.2i - adapted to changes of sepfootnotes, bug fix in reading of multiple notes 2013/02/22 v0.2j - adaption of `enotez' \endnote command 2013/04/07 v0.2k - bug fix: suppress possible break point between footnote mark and punctuation mark if `punct-after=true' has been set 2013/04/16 v0.3 - adapt \footref if it exists - new: \AdaptNoteNoOpt, \AdaptNoteNoOptNoMult 2013/06/14 v0.3a - various internal commands needed to be defined protected 2013/12/22 v0.4 - when biblatex's \autocite is adapted a fix was needed: it calls \footnote eventually which inserted `before-footnote-space' when it shouldn't - adapt to French language settings - clearer distinction between internal commands and document commands 2013/12/23 v0.4a - fix bug introcuded in v0.4 due to a typo 2014/03/10 v0.4b - adapt to version 1.2 of package `translations' - adapt to update to `tablefootnote' - bug fix: add missing penalty that caused a footnote marker to be placed on the following line in some instances 2015/02/20 v0.4c - adapt to update to `sepfootnotes' (quicknotes) - bug fix (looking ahead for known note commands works again) 2015/04/23 v0.4d - fix for issue #7: polyglossia and french 2016/03/25 v0.4e - fix for issue #9 2019/02/17 v0.4f - fix for issues #13 and #19 2019/09/30 v0.4g - update for expl3 deprecations 2019/10/05 v0.5 - fix issue 18 - remove option `bigfoot-default-top' - support `manyfoot' package 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) 2022/01/04 v1.0a - correct file hooks 2022/01/29 v1.0b - remove erroneously inserted horizontal skip 2022/02/03 v1.1 - add \fnpct_unspace: (similar/equal to biblatex's \unspace), see https://tex.stackexchange.com/questions/467561/ - new option `mult-variant-prefix' - new option `unspace' 2022/02/27 v1.1a - fix bug in \fnpct_unspace: - fix bug in sepfootnotes adaption - add package check file - use \DeclareCommandCopy for saving the original note commands - use LaTeX's release mechanism