summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/postnotes/postnotes.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'macros/latex/contrib/postnotes/postnotes.dtx')
-rw-r--r--macros/latex/contrib/postnotes/postnotes.dtx2587
1 files changed, 2587 insertions, 0 deletions
diff --git a/macros/latex/contrib/postnotes/postnotes.dtx b/macros/latex/contrib/postnotes/postnotes.dtx
new file mode 100644
index 0000000000..d817519754
--- /dev/null
+++ b/macros/latex/contrib/postnotes/postnotes.dtx
@@ -0,0 +1,2587 @@
+% \iffalse meta-comment
+%
+% File: postnotes.dtx
+%
+% This file is part of the LaTeX package "postnotes".
+%
+% Copyright (C) 2022 Gustavo Barros
+%
+% It may be distributed and/or modified under the conditions of the
+% LaTeX Project Public License (LPPL), either version 1.3c of this
+% license or (at your option) any later version. The latest version
+% of this license is in the file:
+%
+% https://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 is "maintained" (as per LPPL maintenance status) by
+% Gustavo Barros.
+%
+% This work consists of the files postnotes.dtx,
+% postnotes.ins,
+% postnotes.tex,
+% postnotes-code.tex,
+% and the files generated from them.
+%
+% The released version of this package is available from CTAN.
+%
+% -----------------------------------------------------------------------
+%
+% The development version of the package can be found at
+%
+% https://github.com/gusbrs/postnotes
+%
+% for those people who are interested.
+%
+% -----------------------------------------------------------------------
+%
+% \fi
+%
+% \iffalse
+%<*driver>
+\documentclass{l3doc}
+
+% Have \GetFileInfo pick up date and version data and used in the
+% documentation.
+\usepackage{postnotes}
+
+\begin{document}
+
+\DocInput{postnotes.dtx}
+
+\end{document}
+%</driver>
+%
+% \fi
+%
+% \DoNotIndex{\\}
+%
+% \NewDocumentCommand\githubissue{m}{^^A
+% issue~\href{https://github.com/gusbrs/postnotes/issues/#1}{\##1}}
+%
+% \NewDocumentCommand\githubPR{m}{^^A
+% PR~\href{https://github.com/gusbrs/postnotes/pull/#1}{\##1}}
+%
+% ^^A Currently just for keeping semantic markup on this.
+% \NewDocumentCommand\contributor{m}{#1}
+%
+% \NewDocumentCommand\opt{m}{\texttt{#1}}
+%
+% \pdfstringdefDisableCommands{^^A
+% \def\opt#1{#1}
+% }
+%
+% \AddToHook{env/macro/after}{\medskip{}}
+% \AddToHook{env/variable/after}{\medskip{}}
+% \AddToHook{env/function/after}{\medskip{}}
+%
+%
+% ^^A Have the Index at 'section' level rather than 'part'. Otherwise it is
+% ^^A just the same definition from 'l3doc.cls'.
+% \IndexPrologue{^^A
+% \section*{Index}
+% \markboth{Index}{Index}
+% \addcontentsline{toc}{section}{Index}
+% The italic numbers denote the pages where the corresponding entry is
+% described, numbers underlined point to the definition, all others indicate
+% the places where it is used.^^A
+% }
+%
+%
+% \GetFileInfo{postnotes.sty}
+%
+% \title{^^A
+% The \pkg{postnotes} package^^A
+% \thanks{This file describes \fileversion, released \filedate.}^^A
+% \texorpdfstring{\\{}\medskip{}}{ - }^^A
+% Code documentation^^A
+% \texorpdfstring{\medskip{}}{}^^A
+% }
+%
+% \author{^^A
+% Gustavo Barros^^A
+% \thanks{\url{https://github.com/gusbrs/postnotes}}^^A
+% }
+%
+% \date{\filedate}
+%
+% \maketitle
+%
+%
+% \tableofcontents
+%
+%
+% \clearpage{}
+%
+% \section{Initial setup}
+% Start the \pkg{DocStrip} guards.
+% \begin{macrocode}
+%<*package>
+% \end{macrocode}
+%
+% Identify the internal prefix (\LaTeX3 \pkg{DocStrip} convention).
+% \begin{macrocode}
+%<@@=postnotes>
+% \end{macrocode}
+%
+%
+% Require the new syntax for file/package hooks (\texttt{ltnews34},
+% \texttt{ltfilehook}).
+%
+% \begin{macrocode}
+\providecommand\IfFormatAtLeastTF{\@ifl@t@r\fmtversion}
+\IfFormatAtLeastTF{2021-11-15}
+ {}
+ {%
+ \PackageError{postnotes}{LaTeX kernel too old}
+ {%
+ 'postnotes' requires a LaTeX kernel 2021-11-15 or newer.%
+ \MessageBreak Loading will abort!%
+ }%
+ \endinput
+ }%
+% \end{macrocode}
+%
+%
+% \begin{macrocode}
+\ProvidesExplPackage {postnotes} {2022-04-21} {0.1.1}
+ {Endnotes for LaTeX}
+% \end{macrocode}
+%
+%
+% \section{Data}
+%
+%
+% \begin{macro}[EXP]{\@@_data_name:n}
+% Returns the name of the property list variable which stores the data of
+% the \cs{postnote} with \meta{note id} number.
+% \begin{syntax}
+% \cs{@@_data_name:n} \Arg{note id}
+% \end{syntax}
+% \begin{macrocode}
+\cs_new:Npn \@@_data_name:n #1
+ { g_@@_ #1 _data_prop }
+\cs_generate_variant:Nn \@@_data_name:n { e }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\@@_store:nn}
+% Stores the metadata and \meta{note content} of \cs{postnote} with ID
+% \meta{note id}, from where it is called. The
+% \texttt{postnotes/store/note} hook is intended to add further data to the
+% note, when required to support packages with specific needs.
+% \begin{syntax}
+% \cs{@@_store:nn} \Arg{note id} \Arg{note content}
+% \end{syntax}
+% \begin{macrocode}
+\NewHook { postnotes/store/note }
+\cs_new_protected:Npn \@@_store:nn #1#2
+ {
+ \prop_new:c { \@@_data_name:e {#1} }
+ \prop_gput:cnn { \@@_data_name:e {#1} } { type } { note }
+ \prop_gput:cnx { \@@_data_name:e {#1} } { mark }
+ { \l_@@_mark_tl }
+ \prop_gput:cnx { \@@_data_name:e {#1} } { counter }
+ { \int_use:N \c@postnote }
+ \prop_gput:cnx { \@@_data_name:e {#1} } { sortnum }
+ {
+ \bool_if:NTF \l_@@_manual_sortnum_bool
+ { \fp_use:N \l_@@_sort_num_fp }
+ { \int_use:N \c@postnote }
+ }
+ \cs_if_exist:cT { chapter }
+ {
+ \prop_gput:cnx { \@@_data_name:e {#1} }
+ { thechapter } { \thechapter }
+ }
+ \prop_gput:cnx { \@@_data_name:e {#1} } { thesection }
+ { \thesection }
+ \prop_gput:cnx { \@@_data_name:e {#1} } { pnsectname }
+ { \g_@@_section_name_tl }
+ \prop_gput:cnx { \@@_data_name:e {#1} } { pnsectid }
+ { \int_use:N \g_@@_sectid_int }
+ \prop_gput:cnx { \@@_data_name:e {#1} } { multibool }
+ { \bool_to_str:N \l_@@_maybe_multi_bool }
+ \prop_gput:cnn { \@@_data_name:e {#1} } { content } {#2}
+ \UseHook { postnotes/store/note }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\@@_store_section:nn}
+% Stores the metadata and \meta{note content} of \cs{postnotesection} with
+% ID \meta{note id}, from where it is called.
+% \begin{syntax}
+% \cs{@@_store_section:nn} \Arg{note id} \Arg{note content}
+% \end{syntax}
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_store_section:nn #1#2
+ {
+ \prop_new:c { \@@_data_name:e {#1} }
+ \prop_gput:cnn { \@@_data_name:e {#1} } { type } { section }
+ \cs_if_exist:cT { chapter }
+ {
+ \prop_gput:cnx { \@@_data_name:e {#1} }
+ { thechapter } { \thechapter }
+ }
+ \prop_gput:cnx { \@@_data_name:e {#1} } { thesection }
+ { \thesection }
+ \prop_gput:cnn { \@@_data_name:e {#1} } { content } {#2}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}
+% {
+% \@@_prop_get:nnN ,
+% \@@_prop_item:nn ,
+% \@@_prop_gclear:n ,
+% }
+% Convenience functions to retrieve and clear data from a note based on the
+% ID number.
+% \begin{syntax}
+% \cs{@@_prop_get:nnN} \Arg{note id} \Arg{property} \Arg{tl var to set}
+% \cs{@@_prop_item:nn} \Arg{note id} \Arg{property}
+% \cs{@@_prop_gclear:n} \Arg{note id}
+% \end{syntax}
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_prop_get:nnN #1#2#3
+ {
+ \prop_get:cnNF { \@@_data_name:e {#1} } {#2} #3
+ { \tl_clear:N #3 }
+ }
+\cs_new:Npn \@@_prop_item:nn #1#2
+ { \prop_item:cn { \@@_data_name:e {#1} } {#2} }
+\cs_new_protected:Npn \@@_prop_gclear:n #1
+ { \prop_gclear:c { \@@_data_name:e {#1} } }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}[int]{\post@note}
+% The \cs{newlabel} equivalent for \pkg{postnotes}. Based on the kernel's
+% \cs{@newl@bel} so that we get \LaTeX{} checks for multiple and changed
+% references for free (procedure learnt from \pkg{zref}). \cs{post@note},
+% when the \file{.aux} file is read, defines macros named
+% \texttt{\textbackslash{}postnote@r@\meta{label name}}, according to the
+% prefix set by \cs{c_@@_ref_prefix_tl}.
+% \begin{syntax}
+% \cs{post@note} \Arg{label name} \Arg{label content}
+% \end{syntax}
+% \begin{macrocode}
+\tl_const:Nn \c_@@_ref_prefix_tl { postnote@r }
+\cs_new_protected:Npx \post@note #1#2
+ { \exp_not:N \@newl@bel { \c_@@_ref_prefix_tl } {#1} {#2} }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}
+% {
+% \@@_set_mark_page_label:n ,
+% \@@_set_text_page_label:n ,
+% \@@_set_print_page_label:n ,
+% }
+% Label setting functions for each pertinent context. They must use
+% \cs{iow_shipout_x:Nn}, since the main information we are interested in is
+% the \texttt{page}.
+% \begin{syntax}
+% \cs{@@_set_mark_page_label:n} \Arg{label name}
+% \cs{@@_set_text_page_label:n} \Arg{label name}
+% \cs{@@_set_print_page_label:n} \Arg{label name}
+% \end{syntax}
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_set_mark_page_label:n #1
+ {
+ \iow_shipout_x:Nn \@auxout
+ { \post@note { mark@ #1 } { \thepage } }
+ }
+\cs_generate_variant:Nn \@@_set_mark_page_label:n { x }
+\cs_new_protected:Npn \@@_set_text_page_label:n #1
+ {
+ \iow_shipout_x:Nn \@auxout
+ { \post@note { text@ #1 } { \int_use:N \c@page } }
+ }
+\cs_generate_variant:Nn \@@_set_text_page_label:n { x }
+\cs_new_protected:Npn \@@_set_print_page_label:n #1
+ {
+ \iow_shipout_x:Nn \@auxout
+ { \post@note { print@ #1 } { \int_use:N \c@page } }
+ }
+\cs_generate_variant:Nn \@@_set_print_page_label:n { x }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}
+% {
+% \@@_get_pageref:Nn ,
+% \@@_extract_pageref:n ,
+% }
+% Reference data extraction functions.
+% \begin{syntax}
+% \cs{@@_get_pageref:Nn} \Arg{tl var to set} \Arg{label name}
+% \cs{@@_extract_pageref:n} \Arg{label name}
+% \end{syntax}
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_get_pageref:Nn #1#2
+ {
+ \cs_if_exist:cTF { \c_@@_ref_prefix_tl @ #2 }
+ { \tl_set:Nv #1 { \c_@@_ref_prefix_tl @ #2 } }
+ { \tl_clear:N #1 }
+ }
+\cs_generate_variant:Nn \@@_get_pageref:Nn { Nx }
+\cs_new:Npn \@@_extract_pageref:n #1
+ {
+ \cs_if_exist:cTF { \c_@@_ref_prefix_tl @ #1 }
+ { \exp_not:v { \c_@@_ref_prefix_tl @ #1 } }
+ { \c_empty_tl }
+ }
+\cs_generate_variant:Nn \@@_extract_pageref:n { e }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \section{Options}
+%
+% \subsection*{\opt{heading} option}
+%
+% \begin{macrocode}
+\keys_define:nn { postnotes/setup }
+ {
+ heading .cs_set_protected:Np = \pnheading ,
+ heading .value_required:n = true ,
+ }
+% \end{macrocode}
+%
+% \begin{macro}[int]{\pnheading}
+% Provide default value for \cs{pnheading}.
+% \begin{macrocode}
+\cs_if_exist:cTF { chapter }
+ {
+ \cs_new_protected:Npn \pnheading
+ {
+ \chapter*{\pntitle}
+ \@mkboth{\pnheaderdefault}{\pnheaderdefault}
+ }
+ }
+ {
+ \cs_new_protected:Npn \pnheading
+ {
+ \section*{\pntitle}
+ \@mkboth{\pnheaderdefault}{\pnheaderdefault}
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \subsection*{\opt{format} option}
+%
+% \begin{macrocode}
+\tl_new:N \l_@@_print_format_tl
+\keys_define:nn { postnotes/setup }
+ {
+ format .tl_set:N = \l_@@_print_format_tl ,
+ format .initial:n = { \small } ,
+ format .value_required:n = true ,
+ }
+% \end{macrocode}
+%
+%
+% \subsection*{\opt{listenv} option}
+%
+% \begin{macrocode}
+\tl_new:N \l_@@_print_env_tl
+\bool_new:N \l_@@_print_as_list_bool
+\keys_define:nn { postnotes/setup }
+ {
+ listenv .code:n =
+ {
+ \tl_if_eq:nnTF {#1} { none }
+ {
+ \bool_set_false:N \l_@@_print_as_list_bool
+ \tl_set:Nn \l_@@_post_printnote_tl { \par }
+% \end{macrocode}
+% A sensible default just in case. It should not get to be used though.
+% \begin{macrocode}
+ \tl_set:Nn \l_@@_print_env_tl { itemize }
+ }
+ {
+ \bool_set_true:N \l_@@_print_as_list_bool
+ \tl_set:Nn \l_@@_print_env_tl {#1}
+ }
+ } ,
+ listenv .initial:n = { postnoteslist } ,
+ listenv .value_required:n = true ,
+ }
+% \end{macrocode}
+%
+%
+% A couple of built-in list environments provided for convenience, and
+% \texttt{postnoteslist} as default. The horizontal setup of the label in
+% these lists is based on the \texttt{description} environment of the standard
+% classes (see the \emph{The \LaTeX{} Companion}).
+%
+% \begin{macrocode}
+\NewDocumentEnvironment { postnoteslist } { }
+ {
+ \list { }
+ {
+ \setlength { \leftmargin } { 0pt }
+ \setlength { \labelwidth } { 0pt }
+ \setlength { \itemindent } { .5\parindent }
+ \cs_set_eq:NN \makelabel \@@_list_makelabel:n
+ \setlength { \rightmargin } { 0pt }
+ \setlength { \listparindent } { \parindent }
+ \setlength { \parsep } { \parskip }
+ \setlength { \itemsep } { 0pt }
+ \setlength { \topsep } { .5\topsep }
+ \setlength { \partopsep } { .5\partopsep }
+ }
+ }
+ { \endlist }
+\NewDocumentEnvironment { postnoteslisthang } { }
+ {
+ \list { }
+ {
+ \setlength { \leftmargin } { 1em }
+ \setlength { \labelwidth } { -\leftmargin }
+ \setlength { \itemindent } { -2\leftmargin }
+ \cs_set_eq:NN \makelabel \@@_list_makelabel:n
+ \setlength { \rightmargin } { 0pt }
+ \setlength { \listparindent } { \parindent }
+ \setlength { \parsep } { \parskip }
+ \setlength { \itemsep } { 0pt }
+ \setlength { \topsep } { .5\topsep }
+ \setlength { \partopsep } { .5\partopsep }
+ }
+ }
+ { \endlist }
+\cs_new:Npn \@@_list_makelabel:n #1
+ { \hspace { \labelsep } \normalfont ~ #1 }
+% \end{macrocode}
+%
+%
+% \subsection*{\opt{makemark} and \opt{maketextmark} options}
+%
+% The arguments are: \texttt{\#1} is the mark, \texttt{\#2} and \texttt{\#3}
+% are, respectively, the start and the end of the backlink.
+%
+% \begin{macrocode}
+\keys_define:nn { postnotes/setup }
+ {
+ makemark .cs_set:Np = \@@_make_mark:nnn #1#2#3 ,
+ makemark .value_required:n = true ,
+% \end{macrocode}
+% From the default kernel definition of \cs{@makefnmark}.
+% \begin{macrocode}
+ makemark .initial:n =
+ { #2 \hbox { \@textsuperscript { \normalfont #1 } } #3 } ,
+ maketextmark .cs_set:Np = \@@_make_text_mark:nnn #1#2#3 ,
+ maketextmark .value_required:n = true ,
+ maketextmark .initial:n = { #2 #1 . #3 } ,
+ }
+% \end{macrocode}
+%
+%
+% \subsection*{\opt{pretextmark}, \opt{posttextmark}, \opt{postprintnote} options}
+%
+% \begin{macrocode}
+\tl_new:N \l_@@_pre_textmark_tl
+\tl_new:N \l_@@_post_textmark_tl
+\tl_new:N \l_@@_post_printnote_tl
+\keys_define:nn { postnotes/setup }
+ {
+ pretextmark .tl_set:N = \l_@@_pre_textmark_tl ,
+ pretextmark .value_required:n = true ,
+ posttextmark .tl_set:N = \l_@@_post_textmark_tl ,
+ posttextmark .value_required:n = true ,
+ postprintnote .tl_set:N = \l_@@_post_printnote_tl ,
+ postprintnote .value_required:n = true ,
+ }
+% \end{macrocode}
+%
+%
+% \subsection*{\opt{hyperref} and \opt{backlink} options}
+%
+% \begin{macrocode}
+\bool_new:N \l_@@_hyperlink_bool
+\bool_new:N \l_@@_hyperref_warn_bool
+\bool_new:N \l_@@_backlink_bool
+\keys_define:nn { postnotes/setup }
+ {
+ hyperref .choice: ,
+ hyperref / auto .code:n =
+ {
+ \bool_set_true:N \l_@@_hyperlink_bool
+ \bool_set_false:N \l_@@_hyperref_warn_bool
+ } ,
+ hyperref / true .code:n =
+ {
+ \bool_set_true:N \l_@@_hyperlink_bool
+ \bool_set_true:N \l_@@_hyperref_warn_bool
+ } ,
+ hyperref / false .code:n =
+ {
+ \bool_set_false:N \l_@@_hyperlink_bool
+ \bool_set_false:N \l_@@_hyperref_warn_bool
+ } ,
+ hyperref .initial:n = auto ,
+ hyperref .default:n = true ,
+ backlink .bool_set:N = \l_@@_backlink_bool ,
+ backlink .initial:n = true ,
+ backlink .default:n = true ,
+ }
+% \end{macrocode}
+%
+% \begin{macrocode}
+\AddToHook { begindocument }
+ {
+ \IfPackageLoadedTF { hyperref }
+ { }
+ {
+ \bool_if:NT \l_@@_hyperref_warn_bool
+ { \msg_warning:nn { postnotes } { missing-hyperref } }
+ \bool_set_false:N \l_@@_hyperlink_bool
+ }
+ \keys_define:nn { postnotes/setup }
+ {
+ hyperref .code:n =
+ {
+ \msg_warning:nnn { postnotes }
+ { option-preamble-only } { hyperref }
+ } ,
+ backlink .code:n =
+ {
+ \msg_warning:nnn { postnotes }
+ { option-preamble-only } { backlink }
+ } ,
+ }
+ }
+\msg_new:nnn { postnotes } { option-preamble-only }
+ { Option~'#1'~only~available~in~the~preamble~\msg_line_context:. }
+\msg_new:nnn { postnotes } { missing-hyperref }
+ { Missing~'hyperref'~package.~Setting~'hyperref=false'. }
+% \end{macrocode}
+%
+%
+% \subsection*{\opt{sort} option}
+%
+% \begin{macrocode}
+\bool_new:N \l_@@_sort_bool
+\keys_define:nn { postnotes/setup }
+ {
+ sort .bool_set:N = \l_@@_sort_bool ,
+ sort .initial:n = true ,
+ sort .default:n = true ,
+ }
+% \end{macrocode}
+%
+%
+% \subsection*{\opt{style} option}
+%
+% \begin{macrocode}
+\keys_define:nn { postnotes/setup }
+ {
+ style .choice: ,
+ style / endnotes .meta:n =
+ {
+ listenv = none ,
+ format =
+ {
+ \footnotesize
+ \setlength { \rightskip } { 0pt }
+ \setlength { \leftskip } { 0pt }
+ \setlength { \parindent } { 1.8em }
+ } ,
+ pretextmark = { \par } ,
+% \end{macrocode}
+% \pkg{endnotes} uses a zero width box to get the desired alignment to the
+% right, but that does not play well with the backlinks, so we have a little
+% more work to do to get this right.
+% \begin{macrocode}
+ maketextmark =
+ {
+ \hbox_set:Nn \l_tmpa_box { \@textsuperscript { \normalfont ##1 } }
+ \skip_horizontal:n { - \box_wd:N \l_tmpa_box }
+ ##2 \box_use:N \l_tmpa_box ##3
+ } ,
+ } ,
+ style / pagenote .meta:n =
+ {
+ listenv = none ,
+ format = { } ,
+ pretextmark = { \par\noindent } ,
+ maketextmark = { { \normalfont ##2 ##1 . ##3 } } ,
+ posttextmark = { ~ } ,
+ } ,
+ }
+% \end{macrocode}
+%
+%
+% \subsection*{\cs{postnotesetup}}
+%
+%
+% \begin{macro}[int]{\postnotesetup}
+% Provide \cs{postnotesetup}.
+% \begin{syntax}
+% \cs{postnotesetup}\marg{options}
+% \end{syntax}
+% \begin{macrocode}
+\NewDocumentCommand \postnotesetup { m }
+ { \keys_set:nn { postnotes/setup } {#1} }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \section{\cs{postnote}}
+%
+% Different from the traditional \cs{footnotemark} / \cs{footnotetext} system,
+% in the context of end notes, the functionality which corresponds to
+% \cs{footnotetext} is simply to store the data to be typeset later. Hence,
+% some of the problems that afflict footnotes do not apply to end notes.
+% Namely, and as far as I can tell, they can be used in ``inner horizontal
+% mode'' (\cs{mbox} etc.), and in math mode, and if the ``text'' will be
+% typeset in the same page as the ``mark'' is of little concern.
+%
+% However, the separation between ``mark'' and ``text'' is still useful in
+% other contexts: floats and contexts where multiple typesetting passes are
+% performed. \contributor{David Carlisle} and \contributor{Ulrike Fischer}
+% shared some thoughts on the matter at the TeX.SX chat:
+% \url{https://chat.stackexchange.com/transcript/message/60754383#60754383}.
+%
+% The interesting questions here are: if they are replaceable in their roles
+% in these contexts and how much would we lose by providing them. In
+% analyzing this, we have to distinguish two situations: when
+% \cs{footnotemark} is called with no argument (and thus steps the counter),
+% and when it is called with the optional argument (and thus refrains from
+% stepping the counter).
+%
+% For floats, the problem they pose is that they may disturb the
+% \emph{ordering} of the notes. This particular issue can be solved by using
+% \cs{footnotemark} without argument, and manually adjusting the counter on
+% subsequent calls to \cs{footnotetext}. A good example of the technique is
+% \url{https://tex.stackexchange.com/a/43694}. True, a user may wish to
+% specify the mark explicitly, but doesn't necessarily need to do it to solve
+% the ordering issue.
+%
+% Multiple typesetting passes of content are much harder. And they abound:
+% the standard classes' \cs{caption} typesets the caption once, if it is
+% short, but twice if it is longer than a line; \pkg{amsmath}'s math
+% environments perform a measuring pass before actually typesetting the
+% equations; \pkg{amsmath}'s \cs{text} macro runs the contents through
+% \cs{mathchoice} (which typesets the contents four times) when in math mode;
+% \pkg{tabularx} and \pkg{tabularray} also perform measuring passes of their
+% tables; so does \pkg{csquotes}' blockquotes; and certainly more that I'm
+% unaware. A number of these places offer some one or another way to mitigate
+% the issue: \pkg{amsmath}, \pkg{tabularx}, \pkg{csquotes} and (optionally)
+% \pkg{tabularray} restore counter values after measuring steps; \pkg{amsmath}
+% offers a boolean to indicate when it is a measuring pass; \pkg{csquotes}
+% offers further handles. But the standard \cs{caption} offers none, and
+% neither does \pkg{amsmath}'s \cs{text} macro. Well, the pkg{caption}
+% package has can disable the multiple passes for \cs{caption} with the option
+% \opt{singlelinecheck}, but it is not reasonable to require it for our
+% purposes, so we must assume the worst case.
+%
+% Enrico Gregorio is categorical in stating that \cs{endnotemark} and
+% \cs{endnotetext} are required for \pkg{enotez} to handle \cs{caption}, which
+% apparently it didn't offer originally: ``The package should implement
+% \cs{endnotemark} and \cs{endnotetext} for this case. According to the
+% documentation, the author deems them to not be needed: he's wrong.''
+% (\url{https://tex.stackexchange.com/a/314937}). See also
+% \url{https://tex.stackexchange.com/a/43794} and
+% \url{https://tex.stackexchange.com/a/358207}.
+%
+% In this scenario, when there's no way around the multiple passes,
+% \cs{footnotemark} can only handle the general case if used with an argument,
+% precisely because it inhibits the stepping of the counter. Otherwise the
+% counter is stepped multiple times, and we'd get the wrong number (and mark).
+% In some circumstances, if we know the number of passes is deterministic, we
+% might get away by adjusting the counter manually (\cs{caption} may be dealt
+% with this way: if we know it to be two lines, we can decrement the counter
+% before it and get correct results, even hyperlinked). But in cases which
+% adjusting the counter is sufficient, end notes can be dealt with in the same
+% way, and doesn't need the separation between ``mark'' and ``text''. So,
+% what is distinctive of the kernel's footnote apparatus, which allows it as
+% much flexibility as one would like, is receiving an arbitrary number as
+% argument and not stepping the counter. And as far as \cs{footnotemark} and
+% \cs{footnotetext}) are concerned, the main point of the optional argument is
+% really to ``manually establish the relation'' between the two of them. So,
+% if \emph{not stepping the counter} is what is needed to handle the general
+% case, is it viable to do so? What would we loose in so doing?
+%
+% When receiving an arbitrary number as argument, as the kernel functionality
+% for footnotes and other endnotes packages do, this value is expected to the
+% printed as such, hence it must correspond to the \texttt{postnote} counter
+% (in our case). But this counter is in the hands of the user, and can be
+% reset along the document, thus its uniqueness cannot be ensured. But not
+% stepping \texttt{postnote} is perfectly viable, as it just aims at storing
+% how the mark is to be typeset. However, not stepping the ID counter would
+% complicate things considerably. Not doing so implies we'd lose the
+% connection we have between the ``mark'' and the corresponding ``text''. We
+% might add the ``text'' to the queue, but all the metadata would be lost,
+% including the \pkg{hyperref} anchor, but really the set of data without
+% which the kind of functionality offered would be nonviable, or severely
+% hampered. Not stepping \texttt{postnote} but stepping the ID counter also
+% is not sufficient, because we'd get a note in duplicity. We could naively
+% think that a gap in the ID is not a problem, and just not add the duplicate
+% to the queue. But how could we tell the difference between a legitimate and
+% an illegitimate step of the ID counter?
+%
+% I have not been able to devise a way to ``reconnect'' ``text'' and ``mark''
+% in the absence of the unique ID counter. The most promising idea was to
+% have mandatory arguments to \cs{postnotemark} and \cs{postnotetext}
+% receiving a \meta{label} which we could use to identify their counterparts,
+% but I was not able to go through with this, and the attempts all increased
+% complexity considerably. It is not just a label/ref system, there's got to
+% be a one-to-one correspondence between the sets, uniqueness has to be
+% ensured on both sides, and there cannot be ``lone'' marks or texts (a
+% bijection). Besides, this label based system of identification would have
+% to live side-by-side with the one based on the counter. So, even if we'd
+% have unique IDs, we wouldn't know beforehand in what form it comes.
+% Considering the ID is used to build the variable name in which we store the
+% note's information, this would also complicate things.
+%
+% Besides, there are ways to get things working with multiple passes without
+% the ``mark''/``text'' partition. As mentioned, there are a number of cases
+% which offer some kind of ``handle'' or way to identify the multiple passes.
+% \pkg{csquotes} has a dedicated hook that can be used. \pkg{amsmath} sets
+% the \texttt{measuring@} boolean (which \pkg{hyperref} also defines). So,
+% not all cases are as tricky as \cs{caption} or \cs{text}, and even that can
+% be decently dealt with without a separation between ``mark'' and ``text''.
+% Besides, in difficult cases, the package offers a \opt{nomark} option to
+% \cs{postnote} to place a note, but typeset no mark. Than we can typeset a
+% mark with \cs{postnoteref} referring to a \cs{label} in the note of
+% interest. This would result in a correct mark without duplicity, and in a
+% correct link from there to the note's text at \cs{printpostnotes}. The
+% drawback is that the placement of \cs{postnote} would be important, and
+% results sensitive to it. All the metadata is collected at the point of
+% \cs{postnote}, anchor included, not at the point of \cs{postnoteref}. So
+% the consequences are a slightly off backlink, possibly imprecise metadata,
+% etc. Considering \pkg{hyperref} itself shies away completely from linking
+% \cs{footnotemark} with an argument, I'd say there's some gain.
+%
+% The truth is there are some trade-offs, there's no ``ideal'' solution.
+% Still, all in all, my judgment is that the unique ID counter is worth more
+% than the inconveniences of an ocasional \texttt{\cs{postnote}[nomark]}
+% referenced with \cs{postnoteref}, and even that should not be needed much.
+% So, for the time being, until something else shakes this balance, I won't be
+% offering \cs{postnotemark} and \cs{postnotetext}.
+%
+% \bigskip{}
+%
+% For the \pkg{hyperref} support for cross-references in \cs{postnote}, I've
+% moved back and forth quite a lot. One of the ideas I fancied was using
+% \cs{refstepcounter} and let \pkg{hyperref} do its job. But, since I want to
+% have control of the anchor/destination name on both ``sides'', I'd have to
+% set \cs{theHpostnote} locally before calling \cs{refstepcounter}, otherwise
+% results might sensitive to user calls to \cs{counterwithin} (see
+% \url{https://github.com/latex3/hyperref/issues/230}, thanks
+% \contributor{Ulrike Fischer}). However, even if that worked well for the
+% default case, we still had to setup things manually, in case of a manually
+% supplied mark. All in all, I'm just calling \cs{stepcounter}, setting the
+% relevant cross-reference variables once and setting the anchor manually.
+%
+%
+% \bigskip{}
+%
+% \texttt{postnote} is the public, user facing, counter for \cs{postnote}. It
+% determines how the note's mark gets to be typeset. It can be reset, set,
+% and have its printed representation changed. Of course, whether those are
+% meaningful is up to the user.
+%
+% \begin{macrocode}
+\newcounter { postnote }
+% \end{macrocode}
+%
+% \begin{macro}
+% {
+% \g_@@_note_id_int ,
+% \l_@@_note_id_tl ,
+% \g_@@_queue_seq ,
+% }
+% \cs{g_@@_note_id_int} is the internal, unique counter which provides the
+% ID number of each note. It ties ``mark'' and ``text'' together, is also
+% the connection between each note and its data, including the content,
+% which is stored in a property list named according to \cs{@@_data_name:n}
+% and the ID number. \cs{l_@@_note_id_tl} is a convenience variable storing
+% the counter's value. \cs{g_@@_queue_seq} stores the sequence of notes'
+% IDs that to be processed by the next call of \cs{printpostnotes}.
+% \begin{macrocode}
+\int_new:N \g_@@_note_id_int
+\tl_new:N \l_@@_note_id_tl
+\tl_set:Nn \l_@@_note_id_tl { \int_use:N \g_@@_note_id_int }
+\seq_new:N \g_@@_queue_seq
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}[int]{\postnote}
+% Provide \cs{postnote}.
+% \begin{syntax}
+% \cs{postnote} \oarg{options} \marg{note text}
+% \end{syntax}
+% \begin{macrocode}
+\NewDocumentCommand \postnote { O { } +m }
+ { \@@_note:nn {#1} {#2} }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\@@_note:nn}
+% The internal version of \cs{postnote}. The \texttt{postnotes/note/begin}
+% hook is meant to provide a place from where some additional setup for the
+% note can be performed. This is being used for adding support for some
+% features/packages, but can also be used, for example, to add an extra
+% local property for \pkg{zref}.
+% \begin{syntax}
+% \cs{@@_note:nn}\oarg{options}\marg{note content}
+% \end{syntax}
+% \begin{macrocode}
+\NewHook { postnotes/note/begin }
+\cs_new_protected:Npn \@@_note:nn #1#2
+ {
+ \group_begin:
+ \keys_set:nn { postnotes/note } {#1}
+ \@@_inhibit_note:F
+ {
+ \int_gincr:N \g_@@_note_id_int
+ \tl_if_empty:NT \l_@@_mark_tl
+ {
+ \stepcounter { postnote }
+ \tl_set:Nx \l_@@_mark_tl { \thepostnote }
+ }
+ \seq_gput_right:Nx \g_@@_queue_seq
+ { \l_@@_note_id_tl }
+ \UseHook { postnotes/note/begin }
+ \cs_set:Npn \@currentcounter { postnote }
+ \cs_set:Npx \@currentlabel { \p@postnote \l_@@_mark_tl }
+ \@@_hyperref_make_currentHref:n
+ { postnote. \l_@@_note_id_tl .mark }
+ \@@_set_mark_page_label:x { \l_@@_note_id_tl }
+ \@@_set_user_labels:
+ \bool_if:NTF \l_@@_nomark_bool
+ {
+ \bool_if:NT \l_@@_hyperlink_bool
+ {
+ \@@_hyperref_set_anchor:n
+ { postnote. \l_@@_note_id_tl .mark }
+ }
+ }
+ {
+ \@@_typeset_mark:xV
+ { \l_@@_note_id_tl } \l_@@_mark_tl
+ }
+ \@@_store:nn { \l_@@_note_id_tl } {#2}
+ }
+ \group_end:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% Options for \cs{postnote}.
+%
+% \begin{macrocode}
+\tl_new:N \l_@@_mark_tl
+\bool_new:N \l_@@_nomark_bool
+\fp_new:N \l_@@_sort_num_fp
+\tl_new:N \l_@@_note_label_tl
+\bool_new:N \l_@@_manual_sortnum_bool
+\bool_new:N \l_@@_maybe_multi_bool
+\keys_define:nn { postnotes/note }
+ {
+ mark .tl_set:N = \l_@@_mark_tl ,
+ mark .value_required:n = true ,
+ nomark .bool_set:N = \l_@@_nomark_bool ,
+ nomark .default:n = true ,
+ sortnum .code:n =
+ {
+ \fp_set:Nn \l_@@_sort_num_fp {#1}
+ \bool_set_true:N \l_@@_manual_sortnum_bool
+ } ,
+ sortnum .value_required:n = true ,
+ label .tl_set:N = \l_@@_note_label_tl ,
+ label .value_required:n = true ,
+ }
+% \end{macrocode}
+%
+%
+% \begin{macro}{\@@_inhibit_note:TF}
+% In contexts of multiple passes of content, it may be needed, or preferred,
+% to inhibit the note altogether to avoid side effects and duplicity. This
+% conditional, obviously, will always return the true branch unless
+% something is done in the \texttt{postnotes/note/inhibit} hook. This hook
+% is meant to handle support for packages or features which may justify note
+% inhibition, and the code there should set \cs{l_@@_inhibit_note_bool} and
+% \cs{l_@@_print_plain_mark_bool} as appropriate to the case.
+% \begin{macrocode}
+\bool_new:N \l_@@_inhibit_note_bool
+\bool_new:N \l_@@_print_plain_mark_bool
+\NewHook { postnotes/note/inhibit }
+\prg_new_protected_conditional:Npnn \@@_inhibit_note: { F }
+ {
+ \bool_set_false:N \l_@@_inhibit_note_bool
+ \bool_set_false:N \l_@@_print_plain_mark_bool
+ \UseHook { postnotes/note/inhibit }
+% \end{macrocode}
+% Printing a plain mark here may be needed because, if we are inhibiting the
+% note in a ``measuring context'' and omit it completely, the measuring being
+% performed will be off by the size of the mark. So, to ensure the measuring
+% can be done correctly, we place the mark. Since we'd only print this mark
+% in case of inhibition, when we don't actually step the counter, to typeset
+% correctly the mark that would be printed if the counter had been stepped, we
+% increment \cs{c@postnote} locally and grouped, and smuggle \cs{thepostnote}
+% out of the group.
+% \begin{macrocode}
+ \bool_if:NT \l_@@_print_plain_mark_bool
+ {
+ \tl_if_empty:NT \l_@@_mark_tl
+ {
+ \group_begin:
+ \int_incr:N \c@postnote
+ \exp_args:NNNx
+ \group_end:
+ \tl_set:Nn \l_@@_mark_tl { \thepostnote }
+ }
+ \@@_typeset_mark_wrapper:n
+ { \@@_make_mark:nnn { \l_@@_mark_tl } { } { } }
+ }
+ \bool_if:NTF \l_@@_inhibit_note_bool
+ { \prg_return_true: }
+ { \prg_return_false: }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}
+% {
+% \@@_typeset_mark:nn ,
+% \@@_typeset_mark_wrapper:n ,
+% }
+% Auxiliary functions for mark typesetting in \cs{@@_note:nn}.
+% \cs{@@_typeset_mark_wrapper:n} is based on the definition of
+% \cs{@footnotemark} in the kernel.
+% \begin{syntax}
+% \cs{@@_typeset_mark:nn} \Arg{note id} \Arg{mark}
+% \cs{@@_typeset_mark_wrapper:n} \Arg{mark}
+% \end{syntax}
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_typeset_mark:nn #1#2
+ {
+ \@@_typeset_mark_wrapper:n
+ {
+ \bool_if:NTF \l_@@_hyperlink_bool
+ {
+ \@@_hyperref_set_anchor:n { postnote. #1 .mark }
+ \@@_make_mark:nnn {#2}
+ { \hyper@linkstart { link } { postnote. #1 .text } }
+ { \hyper@linkend }
+ }
+ { \@@_make_mark:nnn {#2} { } { } }
+ }
+ }
+\cs_generate_variant:Nn \@@_typeset_mark:nn { xV }
+\tl_new:N \l_@@_saved_spacefactor_tl
+\cs_new_protected:Npn \@@_typeset_mark_wrapper:n #1
+ {
+ \mode_leave_vertical:
+ \mode_if_horizontal:T
+ {
+ \tl_set:Nx \l_@@_saved_spacefactor_tl { \the\spacefactor }
+ \nobreak
+ }
+ #1
+ \mode_if_horizontal:T
+ { \spacefactor \l_@@_saved_spacefactor_tl }
+ \scan_stop:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\@@_set_user_labels:}
+% Auxiliary function for user label setting in \cs{@@_note:nn}. Supports
+% the \opt{label} and \opt{zlabel} options of \cs{postnote}.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_set_user_labels:
+ {
+ \tl_if_empty:NF \l_@@_note_label_tl
+ { \exp_args:NV \label \l_@@_note_label_tl }
+ \tl_if_empty:NF \l_@@_note_zlabel_tl
+ { \exp_args:NV \zlabel \l_@@_note_zlabel_tl }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \section{\cs{postnoteref}}
+%
+% \begin{macro}[int]{\postnoteref}
+% Provide \cs{postnoteref}.
+% \begin{syntax}
+% \cs{postnoteref}\meta{*}\marg{label}
+% \end{syntax}
+% \begin{macrocode}
+\NewDocumentCommand \postnoteref { s m }
+ { \@@_note_ref:nn {#1} {#2} }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_note_ref:nn}
+% The internal version of \cs{postnoteref}.
+% \begin{syntax}
+% \cs{@@_note_ref:nn} \Arg{star bool} \Arg{label}
+% \end{syntax}
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_note_ref:nn #1#2
+ {
+ \group_begin:
+ \@@_typeset_mark_wrapper:n
+ {
+ \bool_lazy_and:nnTF
+ { ! #1 }
+ { \l_@@_hyperlink_bool }
+ {
+ \hyperref [#2]
+ { \@@_make_mark:nnn { \ref*{#2} } { } { } }
+ }
+ { \@@_make_mark:nnn { \@@_ref_star:n {#2} } { } { } }
+ }
+ \group_end:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \section{\cs{postnotesection}}
+%
+% \begin{macro}[int]{\postnotesection}
+% Provide \cs{postnotesection}.
+% \begin{syntax}
+% \cs{postnotesection}\oarg{options}\marg{section content}
+% \end{syntax}
+% \begin{macrocode}
+\NewDocumentCommand \postnotesection { O { } +m }
+ { \@@_section:nn {#1} {#2} }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_section:nn}
+% The internal version of \cs{postnotesection}.
+% \begin{syntax}
+% \cs{@@_section:nn} \Arg{options} \Arg{content}
+% \end{syntax}
+% \begin{macrocode}
+\int_new:N \g_@@_sectid_int
+\cs_new_protected:Npn \@@_section:nn #1#2
+ {
+ \group_begin:
+ \int_gincr:N \g_@@_sectid_int
+ \int_gincr:N \g_@@_note_id_int
+ \seq_gput_right:Nx \g_@@_queue_seq { \l_@@_note_id_tl }
+ \tl_gclear:N \g_@@_section_name_tl
+ \keys_set:nn { postnotes/section } {#1}
+ \@@_store_section:nn { \l_@@_note_id_tl } {#2}
+ \group_end:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% Options for \cs{postnotesection}. Actually, I would have preferred to use
+% ``label'' for the \opt{name} option, but I feared I might need it further
+% down the road for the traditional meaning.
+%
+% \begin{macrocode}
+\tl_new:N \g_@@_section_name_tl
+\keys_define:nn { postnotes/section }
+ {
+ name .tl_gset:N = \g_@@_section_name_tl ,
+ name .value_required:n = true ,
+ }
+% \end{macrocode}
+%
+%
+% \section{\cs{printpostnotes}}
+%
+% \begin{macro}[int]{\printpostnotes}
+% Provide \cs{printpostnotes}.
+% \begin{syntax}
+% \cs{printpostnotes}
+% \end{syntax}
+% \begin{macrocode}
+\NewDocumentCommand \printpostnotes { }
+ { \@@_print_notes: }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}[int]
+% {
+% \pnthechapter ,
+% \pnthesection ,
+% \pnthechapternextnote ,
+% \pnthesectionnextnote ,
+% \pnthepage ,
+% }
+% User facing variables, aimed at making available some of the notes' and
+% sections' metadata for the user at specific contexts.
+% \begin{macrocode}
+\tl_new:N \pnthechapter
+\tl_new:N \pnthesection
+\tl_new:N \pnthechapternextnote
+\tl_new:N \pnthesectionnextnote
+\tl_new:N \pnthepage
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% {
+% \g_@@_print_postnotes_int ,
+% \l_@@_print_note_id_tl ,
+% \l_@@_print_note_id_next_tl ,
+% \l_@@_print_counter_tl ,
+% \l_@@_print_mark_tl ,
+% \l_@@_print_type_curr_tl ,
+% \l_@@_print_type_next_tl ,
+% \l_@@_print_type_prev_tl ,
+% \l_@@_print_content_tl ,
+% \l_@@_clear_queue_seq ,
+% }
+% Auxiliary variables for \cs{@@_print_notes:}.
+% \begin{macrocode}
+\int_new:N \g_@@_print_postnotes_int
+\tl_new:N \l_@@_print_note_id_tl
+\tl_new:N \l_@@_print_note_id_next_tl
+\tl_new:N \l_@@_print_counter_tl
+\tl_new:N \l_@@_print_mark_tl
+\tl_new:N \l_@@_print_type_curr_tl
+\tl_new:N \l_@@_print_type_next_tl
+\tl_new:N \l_@@_print_type_prev_tl
+\tl_new:N \l_@@_print_content_tl
+\seq_new:N \l_@@_clear_queue_seq
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \cs{@@_print_notes:} hooks. Both meant at providing points of entry for
+% additional setup, specially to add support to packages and features which
+% require it. The \texttt{postnotes/print/begin} hook is run early in
+% \cs{@@_print_notes:} and only once per call, after the user options have
+% been processed. The \texttt{postnotes/print/eachnote} hook is run once for
+% each note, at the point where environment variables are being set or
+% restored, before the typesetting of either the mark or the text, but within
+% a group of its own of each note.
+%
+% \begin{macrocode}
+\NewHook { postnotes/print/begin }
+\NewHook { postnotes/print/eachnote }
+% \end{macrocode}
+%
+%
+% The \texttt{postnotetext} is a counter used to restore the original value of
+% \texttt{postnote} at the time of printing, for the purposes of
+% cross-referencing, it should be different from \texttt{postnote} if a note
+% may occur inside \cs{printpostnotes}. The \texttt{postnotesection} is a
+% counter which is stepped for every postnote section which gets to be
+% actually typeset. It's aim is to provide a valid ``enclosing counter'' to
+% \texttt{postnote} in the context of \cs{printpostnotes}. Since we don't
+% know where \texttt{postnote} may have been reset along the document, in the
+% general case, we can't rely on any other preexisting counter. This means
+% that the particular value of \texttt{postnotesection} is of little practical
+% meaning, it really is just meant to provide recognizable ``bounds'' for
+% \texttt{postnote} along the printing of the notes. Indeed, it is
+% initialized to a very high value, so that ``marks'' and ``texts'' don't mix
+% in the same reference list, which would occur if the enclosing counters of
+% both belonged to the same range, and with somewhat arbitrary results, since
+% we cannot ensure the step of the enclosing counter along the document
+% matches \texttt{postnotesection}. This is actually a tricky problem from
+% the cross-referencing standpoint: two different things, which should be of
+% the same type, are reset along the document, but shouldn't really be mixed
+% together. They are both \LaTeXe{} counters, since they may be required
+% externally. Their main intended use case is to support \pkg{zref-clever},
+% but in principle they can be of general use.
+%
+% \begin{macrocode}
+\newcounter { postnotetext }
+\newcounter { postnotesection }
+\setcounter { postnotesection } { 10000 }
+% \end{macrocode}
+%
+%
+% \begin{macro}{\@@_print_notes:}
+% The internal version of \cs{printpostnotes}.
+% \begin{syntax}
+% \cs{@@_print_notes:}
+% \end{syntax}
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_print_notes:
+ {
+ \group_begin:
+ \int_gincr:N \g_@@_print_postnotes_int
+ \seq_if_empty:NTF \g_@@_queue_seq
+ { \msg_warning:nn { postnotes } { empty-printpostnotes } }
+ {
+ \pnheading
+ \UseHook { postnotes/print/begin }
+ \tl_set:Nn \l_@@_print_type_prev_tl { open }
+ \seq_set_eq:NN \l_@@_clear_queue_seq \g_@@_queue_seq
+ \@@_verify_multipass:N \g_@@_queue_seq
+ \bool_if:NT \l_@@_sort_bool
+ { \@@_sort_queue:N \g_@@_queue_seq }
+ \bool_gset_true:N \g_@@_header_vars_next_bool
+ \@@_get_headers_data:N \g_@@_queue_seq
+ \@@_set_headers_vars_first:
+% \end{macrocode}
+% Ensure the first note after a heading has paragraph indentation when
+% \opt{listenv} is \texttt{none}. \pkg{endnotes} uses a workaroundish
+% solution in \cs{enoteheading}, setting a box and then skipping back a line.
+% Enrico Gregorio is correct, though, in criticizing it at
+% \url{https://tex.stackexchange.com/q/575905#comment1450213_575915}, and
+% suggests the use of \cs{@afterindenttrue}, which is what \pkg{indentfirst}
+% does (we do the same, just locally).
+% \begin{macrocode}
+ \bool_if:NF \l_@@_print_as_list_bool
+ {
+ \cs_set_eq:NN \@afterindentfalse \@afterindenttrue
+ \@afterindenttrue
+ }
+ \bool_until_do:nn { \seq_if_empty_p:N \g_@@_queue_seq }
+ {
+ \seq_gpop_left:NN \g_@@_queue_seq
+ \l_@@_print_note_id_tl
+ \@@_prop_get:nnN { \l_@@_print_note_id_tl }
+ { type } \l_@@_print_type_curr_tl
+ \tl_if_eq:NnTF \l_@@_print_type_curr_tl { section }
+ { % type_curr = `section'
+ \seq_if_empty:NTF \g_@@_queue_seq
+ {
+ \tl_set:Nn \l_@@_print_note_id_next_tl { noid }
+ \tl_set:Nn \l_@@_print_type_next_tl { close }
+ }
+ {
+ \seq_get_left:NN \g_@@_queue_seq
+ \l_@@_print_note_id_next_tl
+ \@@_prop_get:nnN
+ { \l_@@_print_note_id_next_tl }
+ { type } \l_@@_print_type_next_tl
+ }
+% \end{macrocode}
+% We only process the entry if \texttt{type_next} is \texttt{note}: here are
+% skipped empty sections.
+% \begin{macrocode}
+ \tl_if_eq:NnT \l_@@_print_type_next_tl { note }
+ {
+ \stepcounter { postnotesection }
+ \group_begin:
+ \@@_prop_get:nnN
+ { \l_@@_print_note_id_tl }
+ { thechapter } \pnthechapter
+ \@@_prop_get:nnN
+ { \l_@@_print_note_id_tl }
+ { thesection } \pnthesection
+ \@@_prop_get:nnN
+ { \l_@@_print_note_id_next_tl }
+ { thechapter } \pnthechapternextnote
+ \@@_prop_get:nnN
+ { \l_@@_print_note_id_next_tl }
+ { thesection } \pnthesectionnextnote
+ \@@_prop_get:nnN
+ { \l_@@_print_note_id_tl }
+ { content } \l_@@_print_content_tl
+ \l_@@_print_content_tl
+ \group_end:
+% \end{macrocode}
+% Set \texttt{type_prev} for the next iteration.
+% \begin{macrocode}
+ \tl_set:NV \l_@@_print_type_prev_tl
+ \l_@@_print_type_curr_tl
+ }
+ }
+ { % type_curr = `note'
+ \tl_if_eq:NnF \l_@@_print_type_prev_tl { note }
+ {
+ \bool_if:NTF \l_@@_print_as_list_bool
+ { \exp_args:Nx \begin { \l_@@_print_env_tl } }
+ { \group_begin: }
+ \l_@@_print_format_tl
+ }
+ \group_begin:
+ \UseHook { postnotes/print/eachnote }
+ \@@_get_pageref:Nx \pnthepage
+ { mark@ \l_@@_print_note_id_tl }
+ \@@_prop_get:nnN
+ { \l_@@_print_note_id_tl }
+ { mark } \l_@@_print_mark_tl
+ \@@_prop_get:nnN
+ { \l_@@_print_note_id_tl }
+ { counter } \l_@@_print_counter_tl
+ \@@_prop_get:nnN
+ { \l_@@_print_note_id_tl }
+ { content } \l_@@_print_content_tl
+ \cs_set:Npn \@currentcounter { postnotetext }
+ \int_set:Nn \c@postnotetext
+ { \int_eval:n { \l_@@_print_counter_tl } }
+ \cs_set:Npx \@currentlabel
+ { \p@postnote \l_@@_print_mark_tl }
+ \@@_hyperref_make_currentHref:n
+ { postnote. \l_@@_print_note_id_tl .text }
+ \@@_text_mark_wrapper:n
+ {
+ \@@_set_text_page_label:x
+ { \l_@@_print_note_id_tl }
+ \@@_typeset_text_mark:eV
+ { \l_@@_print_note_id_tl }
+ \l_@@_print_mark_tl
+ }
+ \l_@@_print_content_tl
+ \l_@@_post_printnote_tl
+ \group_end:
+% \end{macrocode}
+% For notes, query for next note's type \texttt{after} the current note was
+% typeset, to handle possible nesting. Even if nesting is not a feature, this
+% should avoid hard crashes related to ``lonely \cs{item}'' or ``extra
+% \cs{endgroup}'' errors, in case it occurs.
+% \begin{macrocode}
+ \seq_if_empty:NTF \g_@@_queue_seq
+ {
+ \tl_set:Nn \l_@@_print_note_id_next_tl { noid }
+ \tl_set:Nn \l_@@_print_type_next_tl { close }
+ }
+ {
+ \seq_get_left:NN \g_@@_queue_seq
+ \l_@@_print_note_id_next_tl
+ \@@_prop_get:nnN
+ { \l_@@_print_note_id_next_tl }
+ { type } \l_@@_print_type_next_tl
+ }
+ \tl_if_eq:NnF \l_@@_print_type_next_tl { note }
+ {
+ \bool_if:NTF \l_@@_print_as_list_bool
+ { \exp_args:Nx \end { \l_@@_print_env_tl } }
+ { \group_end: }
+ }
+% \end{macrocode}
+% Set \texttt{type_prev} for the next iteration.
+% \begin{macrocode}
+ \tl_set:NV \l_@@_print_type_prev_tl
+ \l_@@_print_type_curr_tl
+ }
+ }
+ \AddToHookNext { shipout/after }
+ { \bool_gset_false:N \g_@@_header_vars_next_bool }
+% \end{macrocode}
+% We won't use the variables anymore, clear them to reduce memory usage.
+% Given how we populated \cs{l_@@_clear_queue_seq}, this won't catch nested
+% notes. But it's not worth to conditionally add new items along the way
+% (testing it every iteration) for this. Again, not a feature.
+% \begin{macrocode}
+ \seq_map_inline:Nn \l_@@_clear_queue_seq
+ { \@@_prop_gclear:n { ##1 } }
+ }
+ \group_end:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macrocode}
+\msg_new:nnn { postnotes } { empty-printpostnotes }
+ { Empty~'\iow_char:N\\printpostnotes'~\msg_line_context:. }
+% \end{macrocode}
+%
+%
+% \begin{macro}
+% {
+% \@@_typeset_text_mark:nn ,
+% \@@_text_mark_wrapper:n ,
+% }
+% Auxiliary functions for mark typesetting in \cs{@@_print_notes:}.
+% \begin{syntax}
+% \cs{@@_typeset_text_mark:nn} \Arg{note id} \Arg{mark}
+% \cs{@@_text_mark_wrapper:n} \Arg{mark}
+% \end{syntax}
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_typeset_text_mark:nn #1#2
+ {
+ \bool_if:NTF \l_@@_hyperlink_bool
+ {
+ \@@_hyperref_set_anchor:n { postnote. #1 .text }
+ \bool_if:NTF \l_@@_backlink_bool
+ {
+ \@@_make_text_mark:nnn {#2}
+ { \hyper@linkstart { link } { postnote. #1 .mark } }
+ { \hyper@linkend }
+ }
+ { \@@_make_text_mark:nnn {#2} { } { } }
+ }
+ { \@@_make_text_mark:nnn {#2} { } { } }
+ }
+\cs_generate_variant:Nn \@@_typeset_text_mark:nn { eV }
+\cs_new_protected:Npn \@@_text_mark_wrapper:n #1
+ {
+ \bool_if:NTF \l_@@_print_as_list_bool
+ {
+ \item
+ [ \l_@@_pre_textmark_tl #1 \l_@@_post_textmark_tl ]
+ }
+ { \l_@@_pre_textmark_tl #1 \l_@@_post_textmark_tl }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \subsection*{Print auxiliary}
+%
+% \cs{@@_verify_multipass:N} provides a general procedure for handling cases
+% of multiple passes of content. Ideally, the job should be done at
+% \cs{@@_inhibit_note:F}, if at all possible. But, failing that, we can rely
+% on the fact that \cs{postnote}s of measuring/trial passes don't end up being
+% output and hence don't generate labels in the \file{.aux} file. This is the
+% equivalent for \pkg{postnotes} to the effect of write restrictions for the
+% packages based on external files, which is how they actually handle these
+% cases. However, despite this being a general test, and a reasonable one,
+% I'd like to restrain it's use to the minimum possible. First, using this
+% criterion across the board would result in large swings on the content of
+% \cs{printpostnotes} and spurious warnings in an initial compilation since
+% the labels are not available on the first run. Second, I'd prefer not to
+% interfere with the queue, unless we really need to. Hence, we only apply
+% this check for ``eligible'' items. For signaling this eligibility, the note
+% must have been stored with the \cs{l_@@_maybe_multi_bool} set to
+% \texttt{true}, which is then saved in the \texttt{multibool} property. One
+% implication of this procedure is that, if there are any new notes marked as
+% \texttt{multibool}, (at least) three rounds of compilation will be needed,
+% since the labels of the printed notes will be written only on the second run
+% and the document will thus require a third one to stabilize.
+%
+% \begin{macro}{\@@_verify_multipass:N}
+% \begin{syntax}
+% \cs{@@_verify_multipass:N} \meta{\cs{g_@@_queue_seq}}
+% \end{syntax}
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_verify_multipass:N #1
+ {
+ \group_begin:
+ \seq_clear:N \l_tmpa_seq
+ \seq_map_inline:Nn #1
+ {
+ \@@_prop_get:nnN {##1} { multibool } \l_tmpa_tl
+ \tl_if_eq:NnTF \l_tmpa_tl { true }
+ {
+ \cs_if_exist:cT
+ { \c_@@_ref_prefix_tl @ mark@ ##1 }
+ { \seq_put_right:Nn \l_tmpa_seq {##1} }
+ }
+ { \seq_put_right:Nn \l_tmpa_seq {##1} }
+ }
+ \seq_gset_eq:NN #1 \l_tmpa_seq
+ \group_end:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\@@_sort_queue:N}
+% Sorting function for \cs{@@_print_notes:}.
+% \begin{syntax}
+% \cs{@@_sort_queue:N} \meta{\cs{g_@@_queue_seq}}
+% \end{syntax}
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_sort_queue:N #1
+ {
+ \group_begin:
+ \seq_gsort:Nn #1
+ {
+ \@@_prop_get:nnN {##1} { pnsectid } \l_tmpa_tl
+ \@@_prop_get:nnN {##2} { pnsectid } \l_tmpb_tl
+ \tl_if_eq:NNTF \l_tmpa_tl \l_tmpb_tl
+ {
+ \@@_prop_get:nnN {##1} { type } \l_tmpa_tl
+ \@@_prop_get:nnN {##2} { type } \l_tmpb_tl
+ \bool_lazy_and:nnTF
+ { \str_if_eq_p:Vn \l_tmpa_tl { note } }
+ { \str_if_eq_p:Vn \l_tmpb_tl { note } }
+ {
+ \@@_prop_get:nnN {##1} { sortnum } \l_tmpa_tl
+ \@@_prop_get:nnN {##2} { sortnum } \l_tmpb_tl
+ \fp_compare:nNnTF { \l_tmpa_tl } > { \l_tmpb_tl }
+ { \sort_return_swapped: }
+ { \sort_return_same: }
+ }
+ { \sort_return_same: }
+ }
+ { \sort_return_same: }
+ }
+ \group_end:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \section{Headers}
+%
+% The headers infrastructure of \pkg{postnotes} is comprised of three basic
+% parts:
+%
+% \begin{enumerate}
+% \item For each \cs{postnote}, labels are set storing the \texttt{page} where
+% the note occurs. Each note actually generates a pair of such labels, once
+% when \cs{postnote} is called (with the mark), and another where the note
+% is printed (in \cs{printpostnotes}). The former ones store \cs{thepage},
+% since we want the printed representation of it for typesetting purposes,
+% the latter ones store the value of the \texttt{page} counter, since we
+% don't need to typeset it, but do need to perform algebraic operations with
+% it. These labels are set by \cs{@@_set_mark_page_label:n},
+% \cs{@@_set_text_page_label:n}, and \cs{@@_set_print_page_label:n} at the
+% appropriate places. The set of these labels provides a mapping from each
+% note's ``mark'' and ``text'' to the page where it occurs.
+% \item This information set is processed by \cs{@@_get_headers_data:N} at the
+% beginning of \cs{@@_print_notes:} to identify the first and last note of
+% each page in \cs{printpostnotes}, and to generate a mapping from these
+% first and last notes on each page to the pages where their corresponding
+% marks occur. We also take the opportunity to enrich this mapping with
+% other metadata of each note. So we get also mappings from the first and
+% last note on each page to \cs{thechapter}, \cs{thesection}, and the
+% \opt{name} of the section in which they occur. These mappings are stored
+% in property lists \cs[no-index]{g_@@_header_\meta{info}_first_prop} and
+% \cs[no-index]{g_@@_header_\meta{info}_last_prop} where the \texttt{key} is
+% the page in \cs{printpostnotes} where their note's content is typeset (or
+% rather where it starts to be typeset, it is the page where the text's mark
+% is printed).
+% \item Based on these mappings, along the span of notes section we run
+% \cs{@@_set_headers_vars_next:} at each \texttt{shipout/before} hook to set
+% user facing variables for the \emph{next} page, which will be available
+% when their heading gets typeset. Given that at \texttt{shipout} we can
+% rely on a correct value of the \texttt{page} counter, we use it as
+% \texttt{key} to query the property lists generated in the previous step.
+% These user facing variables are called \cs[no-index]{pnhd\meta{info}first}
+% and \cs[no-index]{pnhd\meta{info}last}. Since we cannot rely on the
+% shipout hook for the first page of \cs{printpostnotes},
+% \cs{@@_set_headers_vars_first:} is run at its beginning to ensure correct
+% values are in place on the first page of the notes section.
+% \end{enumerate}
+%
+% These \cs[no-index]{pnhd\meta{info}first} and
+% \cs[no-index]{pnhd\meta{info}last} variables can then be used to build
+% simple functions which can be passed to mark commands to achieve rich
+% contextual running headers.
+%
+%
+% \begin{macro}[int]
+% {
+% \pnhdpagefirst ,
+% \pnhdpagelast ,
+% \pnhdchapfirst ,
+% \pnhdchaplast ,
+% \pnhdsectfirst ,
+% \pnhdsectlast ,
+% \pnhdnamefirst ,
+% \pnhdnamelast ,
+% }
+% User facing variables, aimed at making available header data for the user.
+% Setting these variables with correct values at the moment the header gets
+% typeset is \emph{the} objective of the whole headers infrastructure of the
+% package.
+% \begin{macrocode}
+\tl_new:N \pnhdpagefirst
+\tl_new:N \pnhdpagelast
+\tl_new:N \pnhdchapfirst
+\tl_new:N \pnhdchaplast
+\tl_new:N \pnhdsectfirst
+\tl_new:N \pnhdsectlast
+\tl_new:N \pnhdnamefirst
+\tl_new:N \pnhdnamelast
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}
+% {
+% \g_@@_header_page_first_prop ,
+% \g_@@_header_page_last_prop ,
+% \g_@@_header_chap_first_prop ,
+% \g_@@_header_chap_last_prop ,
+% \g_@@_header_sect_first_prop ,
+% \g_@@_header_sect_last_prop ,
+% \g_@@_header_name_first_prop ,
+% \g_@@_header_name_last_prop ,
+% \g_@@_header_prev_last_page_tl ,
+% \g_@@_header_prev_last_chap_tl ,
+% \g_@@_header_prev_last_sect_tl ,
+% \g_@@_header_prev_last_name_tl ,
+% \l_@@_prev_text_page_tl ,
+% \l_@@_curr_text_page_tl ,
+% \l_@@_prev_mark_page_tl ,
+% \l_@@_prev_mark_chap_tl ,
+% \l_@@_prev_mark_sect_tl ,
+% \l_@@_prev_mark_name_tl ,
+% }
+% Auxiliary variables for the headers infrastructure.
+% \begin{macrocode}
+\prop_new:N \g_@@_header_page_first_prop
+\prop_new:N \g_@@_header_page_last_prop
+\prop_new:N \g_@@_header_chap_first_prop
+\prop_new:N \g_@@_header_chap_last_prop
+\prop_new:N \g_@@_header_sect_first_prop
+\prop_new:N \g_@@_header_sect_last_prop
+\prop_new:N \g_@@_header_name_first_prop
+\prop_new:N \g_@@_header_name_last_prop
+\tl_new:N \g_@@_header_prev_last_page_tl
+\tl_new:N \g_@@_header_prev_last_chap_tl
+\tl_new:N \g_@@_header_prev_last_sect_tl
+\tl_new:N \g_@@_header_prev_last_name_tl
+\tl_new:N \l_@@_prev_text_page_tl
+\tl_new:N \l_@@_curr_text_page_tl
+\tl_new:N \l_@@_prev_mark_page_tl
+\tl_new:N \l_@@_prev_mark_chap_tl
+\tl_new:N \l_@@_prev_mark_sect_tl
+\tl_new:N \l_@@_prev_mark_name_tl
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\@@_get_headers_data:N}
+% Process header data for \cs{@@_set_headers_vars:n}.
+% \begin{syntax}
+% \cs{@@_get_headers_data:N} \meta{\cs{g_@@_queue_seq}}
+% \end{syntax}
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_get_headers_data:N #1
+ {
+ \group_begin:
+ \tl_gclear:N \pnhdpagefirst
+ \tl_gclear:N \pnhdpagelast
+ \tl_gclear:N \pnhdchapfirst
+ \tl_gclear:N \pnhdchaplast
+ \tl_gclear:N \pnhdsectfirst
+ \tl_gclear:N \pnhdsectlast
+ \tl_gclear:N \pnhdnamefirst
+ \tl_gclear:N \pnhdnamelast
+ \prop_gclear:N \g_@@_header_page_first_prop
+ \prop_gclear:N \g_@@_header_page_last_prop
+ \prop_gclear:N \g_@@_header_chap_first_prop
+ \prop_gclear:N \g_@@_header_chap_last_prop
+ \prop_gclear:N \g_@@_header_sect_first_prop
+ \prop_gclear:N \g_@@_header_sect_last_prop
+ \prop_gclear:N \g_@@_header_name_first_prop
+ \prop_gclear:N \g_@@_header_name_last_prop
+ \tl_gclear:N \g_@@_header_prev_last_page_tl
+ \tl_gclear:N \g_@@_header_prev_last_chap_tl
+ \tl_gclear:N \g_@@_header_prev_last_sect_tl
+ \tl_gclear:N \g_@@_header_prev_last_name_tl
+ \tl_clear:N \l_@@_prev_text_page_tl
+ \tl_clear:N \l_@@_curr_text_page_tl
+ \tl_clear:N \l_@@_prev_mark_page_tl
+ \tl_clear:N \l_@@_prev_mark_chap_tl
+ \tl_clear:N \l_@@_prev_mark_sect_tl
+ \tl_clear:N \l_@@_prev_mark_name_tl
+ \seq_map_inline:Nn #1
+ {
+ \exp_args:Nx \tl_if_eq:nnT
+ { \@@_prop_item:nn {##1} { type } }
+ { note }
+ {
+ \@@_get_pageref:Nn
+ \l_@@_curr_text_page_tl { text@ ##1 }
+ \tl_if_empty:NF \l_@@_curr_text_page_tl
+ {
+ \tl_if_eq:NNTF
+ \l_@@_prev_text_page_tl
+ \l_@@_curr_text_page_tl
+ {
+% \end{macrocode}
+% We are on the same page as the previous note, just update the
+% \texttt{prev_mark} data.
+% \begin{macrocode}
+ \@@_get_pageref:Nn
+ \l_@@_prev_mark_page_tl { mark@ ##1 }
+ \@@_prop_get:nnN {##1} { thechapter }
+ \l_@@_prev_mark_chap_tl
+ \@@_prop_get:nnN {##1} { thesection }
+ \l_@@_prev_mark_sect_tl
+ \@@_prop_get:nnN {##1} { pnsectname }
+ \l_@@_prev_mark_name_tl
+ }
+ {
+% \end{macrocode}
+% We are on the transition between two pages, current ID is the first note of
+% the new page (or on the very first note of \cs{printpostnotes}, given
+% \cs{l_@@_prev_text_page_tl} is initialized to empty).
+%
+% Set `last' values for previous page, based on the last valid
+% \texttt{prev_mark} stored ones. There is no previous page to the first one
+% of \cs{printpostnotes}, so we don't set `last' values for it (conditioning
+% on \cs{l_@@_prev_text_page_tl} being empty, which only occurs on the first
+% note).
+% \begin{macrocode}
+ \tl_if_empty:NF \l_@@_prev_text_page_tl
+ {
+ \prop_gput:Nxx \g_@@_header_page_last_prop
+ { \l_@@_prev_text_page_tl }
+ { \l_@@_prev_mark_page_tl }
+ \prop_gput:Nxx \g_@@_header_chap_last_prop
+ { \l_@@_prev_text_page_tl }
+ { \l_@@_prev_mark_chap_tl }
+ \prop_gput:Nxx \g_@@_header_sect_last_prop
+ { \l_@@_prev_text_page_tl }
+ { \l_@@_prev_mark_sect_tl }
+ \prop_gput:Nxx \g_@@_header_name_last_prop
+ { \l_@@_prev_text_page_tl }
+ { \l_@@_prev_mark_name_tl }
+ }
+% \end{macrocode}
+%
+% Set `first' values for current page, based on the current note ID.
+% \begin{macrocode}
+ \prop_gput:Nxx \g_@@_header_page_first_prop
+ { \l_@@_curr_text_page_tl }
+ { \@@_extract_pageref:n { mark@ ##1 } }
+ \prop_gput:Nxx \g_@@_header_chap_first_prop
+ { \l_@@_curr_text_page_tl }
+ { \@@_prop_item:nn {##1} { thechapter } }
+ \prop_gput:Nxx \g_@@_header_sect_first_prop
+ { \l_@@_curr_text_page_tl }
+ { \@@_prop_item:nn {##1} { thesection } }
+ \prop_gput:Nxx \g_@@_header_name_first_prop
+ { \l_@@_curr_text_page_tl }
+ { \@@_prop_item:nn {##1} { pnsectname } }
+% \end{macrocode}
+%
+% Store \texttt{prev_mark} data for the first note on the page.
+% \begin{macrocode}
+ \@@_get_pageref:Nn
+ \l_@@_prev_mark_page_tl { mark@ ##1 }
+ \@@_prop_get:nnN {##1} { thechapter }
+ \l_@@_prev_mark_chap_tl
+ \@@_prop_get:nnN {##1} { thesection }
+ \l_@@_prev_mark_sect_tl
+ \@@_prop_get:nnN {##1} { pnsectname }
+ \l_@@_prev_mark_name_tl
+% \end{macrocode}
+%
+% Set \cs{l_@@_prev_text_page_tl} for the next page
+% (\cs{l_@@_curr_text_page_tl} is never empty at this point, since we
+% conditioned to it).
+% \begin{macrocode}
+ \tl_set:NV \l_@@_prev_text_page_tl
+ \l_@@_curr_text_page_tl
+ }
+ }
+ }
+ }
+% \end{macrocode}
+% We can't catch the transition from the last page of \cs{printpostnotes} to
+% the following one through the mapping above, but the \texttt{prev_mark}
+% values of the last note in the loop are the ones we want, so we set `last'
+% values for the last page based on them.
+% \begin{macrocode}
+ \tl_if_empty:NF \l_@@_prev_text_page_tl
+ {
+ \prop_gput:Nxx \g_@@_header_page_last_prop
+ { \l_@@_prev_text_page_tl }
+ { \l_@@_prev_mark_page_tl }
+ \prop_gput:Nxx \g_@@_header_chap_last_prop
+ { \l_@@_prev_text_page_tl }
+ { \l_@@_prev_mark_chap_tl }
+ \prop_gput:Nxx \g_@@_header_sect_last_prop
+ { \l_@@_prev_text_page_tl }
+ { \l_@@_prev_mark_sect_tl }
+ \prop_gput:Nxx \g_@@_header_name_last_prop
+ { \l_@@_prev_text_page_tl }
+ { \l_@@_prev_mark_name_tl }
+ }
+ \group_end:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% The sequence of pages processed in \cs{@@_get_headers_data:N} is not ensured
+% to be continuous, since not every page of \cs{printpostnotes} starts a note.
+% There may be notes that fill whole pages, or the last page of the notes may
+% end with a note that started on the penultimate page. We must handle this
+% case at \cs{@@_set_headers_vars:n}. For every page for which there is
+% information provided by \cs{@@_get_headers_data:N} we store a
+% \texttt{header_prev_last} (the last value of the previous header) for each
+% of the variables of interest. If the next page is skipped in the sequence
+% (no notes starting on it), we can use these stored values to set both
+% `first' and `last' variables based on them for that page.
+%
+%
+% \begin{macro}{\@@_set_headers_vars:n}
+% Set user facing variables based on data generated by
+% \cs{@@_get_headers_data:N}.
+% \begin{syntax}
+% \cs{@@_set_headers_vars:n} \Arg{page number}
+% \end{syntax}
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_set_headers_vars:n #1
+ {
+ \group_begin:
+ \prop_get:NnNTF \g_@@_header_page_first_prop
+ {#1} \l_tmpa_tl
+ { \tl_gset:NV \pnhdpagefirst \l_tmpa_tl }
+ { \tl_gset:NV \pnhdpagefirst \g_@@_header_prev_last_page_tl }
+ \prop_get:NnNTF \g_@@_header_page_last_prop
+ {#1} \l_tmpa_tl
+ {
+ \tl_gset:NV \pnhdpagelast \l_tmpa_tl
+ \tl_gset:NV \g_@@_header_prev_last_page_tl \l_tmpa_tl
+ }
+ { \tl_gset:NV \pnhdpagelast \g_@@_header_prev_last_page_tl }
+ \prop_get:NnNTF \g_@@_header_chap_first_prop
+ {#1} \l_tmpa_tl
+ { \tl_gset:NV \pnhdchapfirst \l_tmpa_tl }
+ { \tl_gset:NV \pnhdchapfirst \g_@@_header_prev_last_chap_tl }
+ \prop_get:NnNTF \g_@@_header_chap_last_prop
+ {#1} \l_tmpa_tl
+ {
+ \tl_gset:NV \pnhdchaplast \l_tmpa_tl
+ \tl_gset:NV \g_@@_header_prev_last_chap_tl \l_tmpa_tl
+ }
+ { \tl_gset:NV \pnhdchaplast \g_@@_header_prev_last_chap_tl }
+ \prop_get:NnNTF \g_@@_header_sect_first_prop
+ {#1} \l_tmpa_tl
+ { \tl_gset:NV \pnhdsectfirst \l_tmpa_tl }
+ { \tl_gset:NV \pnhdsectfirst \g_@@_header_prev_last_sect_tl }
+ \prop_get:NnNTF \g_@@_header_sect_last_prop
+ {#1} \l_tmpa_tl
+ {
+ \tl_gset:NV \pnhdsectlast \l_tmpa_tl
+ \tl_gset:NV \g_@@_header_prev_last_sect_tl \l_tmpa_tl
+ }
+ { \tl_gset:NV \pnhdsectlast \g_@@_header_prev_last_sect_tl }
+ \prop_get:NnNTF \g_@@_header_name_first_prop
+ {#1} \l_tmpa_tl
+ { \tl_gset:NV \pnhdnamefirst \l_tmpa_tl }
+ { \tl_gset:NV \pnhdnamefirst \g_@@_header_prev_last_name_tl }
+ \prop_get:NnNTF \g_@@_header_name_last_prop
+ {#1} \l_tmpa_tl
+ {
+ \tl_gset:NV \pnhdnamelast \l_tmpa_tl
+ \tl_gset:NV \g_@@_header_prev_last_name_tl \l_tmpa_tl
+ }
+ { \tl_gset:NV \pnhdnamelast \g_@@_header_prev_last_name_tl }
+ \group_end:
+ }
+\cs_generate_variant:Nn \@@_set_headers_vars:n { x }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}
+% {
+% \@@_set_headers_vars_next: ,
+% \@@_set_headers_vars_first: ,
+% }
+% The functions that actually call \cs{@@_set_headers_vars:n} at the
+% appropriate contexts with appropriate page values. Though we set
+% \cs{@@_set_headers_vars_next:} to run at every \texttt{shipout/before}
+% hook of the document, it is made no-op by \cs{g_@@_header_vars_next_bool}
+% which only has a \texttt{true} value inside \cs{printpostnotes}.
+% \cs{@@_set_headers_vars_first:} must set a label and retrieve its value to
+% be able to have a reliable value of its own page.
+% \begin{macrocode}
+\AddToHook { shipout/before } [ postnotes/header ]
+ { \@@_set_headers_vars_next: }
+\bool_new:N \g_@@_header_vars_next_bool
+\cs_new_protected:Npn \@@_set_headers_vars_next:
+ {
+ \bool_if:NT \g_@@_header_vars_next_bool
+ { \@@_set_headers_vars:x { \int_eval:n { \c@page + 1 } } }
+ }
+\cs_new_protected:Npn \@@_set_headers_vars_first:
+ {
+ \@@_set_print_page_label:x
+ { \int_use:N \g_@@_print_postnotes_int }
+ \@@_set_headers_vars:x
+ {
+ \@@_extract_pageref:e
+ { print@ \int_use:N \g_@@_print_postnotes_int }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}[int]{\pnheaderdefault}
+% A basic header function to be used as default in the \opt{heading} option.
+% It produces a header in the form ``Notes to pages N--M'', with a text
+% which can be localized (see Section~\ref{sec:languages}).
+% \begin{syntax}
+% \cs{pnheaderdefault}
+% \end{syntax}
+% \begin{macrocode}
+\NewDocumentCommand \pnheaderdefault {}
+ {
+ \tl_if_eq:NNTF \pnhdpagefirst \pnhdpagelast
+ { \pnhdnotes{} ~ \pnhdtopage{} ~ \pnhdpagefirst }
+ { \pnhdnotes{} ~ \pnhdtopages{} ~ \pnhdpagefirst -- \pnhdpagelast }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \section{Compatibility}
+%
+% \subsection*{\cs{caption}}
+%
+% For \cs{caption}'s possible two passes. This catches more than just
+% captions, of course, but is not overkill.
+%
+% From the user's perspective, one-line captions will just work. For two-line
+% captions, there are two alternatives: i) decrement the counter by 1
+% \texttt{\textbackslash{}addtocounter\{postnote\}\{-1\}} before the caption,
+% then call \cs{postnote} inside the caption; or ii) call
+% \texttt{\textbackslash{}postnote[nomark]\{\textbackslash{}label\{mynote\}...\}}
+% right before the caption, then use
+% \texttt{\textbackslash{}postnoteref\{mynote\}} inside the caption.
+%
+% \begin{macrocode}
+\AddToHook { postnotes/note/begin } [ postnotes ]
+ {
+ \cs_if_exist:NT \@captype
+ { \bool_set_true:N \l_@@_maybe_multi_bool }
+ }
+% \end{macrocode}
+%
+%
+% \subsection*{\pkg{hyperref}}
+%
+% \begin{macrocode}
+\bool_new:N \g_@@_hyperref_loaded_bool
+\AddToHook { package/hyperref/after }
+ { \bool_gset_true:N \g_@@_hyperref_loaded_bool }
+% \end{macrocode}
+%
+% \begin{macro}
+% {
+% \@@_hyperref_make_currentHref:n ,
+% \@@_hyperref_set_anchor:n ,
+% \@@_ref_star:n ,
+% }
+% Auxiliary functions for \pkg{hyperref} support.
+% \begin{syntax}
+% \cs{@@_hyperref_make_currentHref:n} \Arg{anchor/destination}
+% \cs{@@_hyperref_set_anchor:n} \Arg{anchor/destination}
+% \cs{@@_ref_star:n} \Arg{label}
+% \end{syntax}
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_hyperref_make_currentHref:n #1
+ {
+ \bool_if:NT \g_@@_hyperref_loaded_bool
+ { \Hy@MakeCurrentHref {#1} }
+ }
+\cs_new_protected:Npn \@@_hyperref_set_anchor:n #1
+ {
+ \bool_if:NT \g_@@_hyperref_loaded_bool
+ { \Hy@raisedlink { \hyper@anchor {#1} } }
+ }
+\cs_new_protected:Npn \@@_ref_star:n #1
+ {
+ \bool_if:NTF \g_@@_hyperref_loaded_bool
+ { \ref*{#1} }
+ { \ref{#1} }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \subsection*{\pkg{biblatex}}
+%
+% Thanks \contributor{Moritz Wemheuer}:
+% \url{https://tex.stackexchange.com/q/597359#comment1594585_597389}.
+%
+% We can make \pkg{biblatex}'s \texttt{refsegment}s and \texttt{refcontext}s
+% work, but \texttt{refsection}s are more complicated. Currently,
+% \texttt{refsection}s are only supported if \cs{printpostnotes} is called
+% within each \texttt{refsection}, one cannot ``accumulate'' the notes from
+% all \texttt{refsection}s and print them at the end. Well, one can, but they
+% will be considered part of the current \texttt{refsection} of wherever
+% \cs{printpostnotes} is placed (unless they were also cited in the original
+% \texttt{refsection} out of a \cs{postnote} which, of course, is not
+% something to rely on).
+%
+% Note that support for these features of \pkg{biblatex} is
+% \emph{experimental}.
+%
+% \begin{macrocode}
+\AddToHook { package/biblatex/after }
+ {
+% \end{macrocode}
+% Store \pkg{biblatex} variables for each note.
+% \begin{macrocode}
+ \AddToHook { postnotes/store/note } [ postnotes ]
+ {
+ \prop_gput:cnx { \@@_data_name:e { \l_@@_note_id_tl } }
+ { biblatex@refsection } { \int_use:N \c@refsection }
+ \prop_gput:cnx { \@@_data_name:e { \l_@@_note_id_tl } }
+ { biblatex@refsegment } { \int_use:N \c@refsegment }
+ \prop_gput:cnx { \@@_data_name:e { \l_@@_note_id_tl } }
+ { biblatex@refcontextbool }
+ { \iftoggle { blx@refcontext } { true } { false } }
+ \prop_gput:cnV { \@@_data_name:e { \l_@@_note_id_tl } }
+ { biblatex@refcontext } \blx@refcontext@context
+ }
+% \end{macrocode}
+% \pkg{biblatex} setup, once for \cs{printpostnotes} call.
+% \begin{macrocode}
+ \AddToHook { postnotes/print/begin } [ postnotes ]
+ {
+ \@@_biblatex_endrefcontext_local:
+ \@@_biblatex_citereset_local:
+% \end{macrocode}
+% Let \pkg{biblatex} know we are in a ``notes'' context. See
+% \url{https://tex.stackexchange.com/a/304464}, including comments.
+% \begin{macrocode}
+ \toggletrue { blx@footnote }
+ }
+% \end{macrocode}
+% Restore \pkg{biblatex} variables for each note.
+% \begin{macrocode}
+ \tl_new:N \l_@@_biblatex_restore_tl
+ \AddToHook { postnotes/print/eachnote } [ postnotes ]
+ {
+ \@@_prop_get:nnN { \l_@@_print_note_id_tl }
+ { biblatex@refsection } \l_@@_biblatex_restore_tl
+ \int_set:Nn \c@refsection { \l_@@_biblatex_restore_tl }
+ \@@_prop_get:nnN { \l_@@_print_note_id_tl }
+ { biblatex@refsegment } \l_@@_biblatex_restore_tl
+ \int_set:Nn \c@refsegment { \l_@@_biblatex_restore_tl }
+ \@@_prop_get:nnN { \l_@@_print_note_id_tl }
+ { biblatex@refcontextbool } \l_@@_biblatex_restore_tl
+ \use:c { toggle \l_@@_biblatex_restore_tl } { blx@refcontext }
+ \@@_prop_get:nnN { \l_@@_print_note_id_tl }
+ { biblatex@refcontext } \l_@@_biblatex_restore_tl
+ \blx@edef@refcontext { \l_@@_biblatex_restore_tl }
+ }
+% \end{macrocode}
+% Make \pkg{biblatex}'s \cs{mkbibendnote} use \cs{postnote}. This is very
+% likely desired in most cases, but may occasionally not be, so we add it to
+% an individually labeled hook, which can be disabled with
+% \texttt{\textbackslash{}RemoveFromHook\{begindocument/before\}[postnotes/mkbibendnote]}
+% in the preamble.
+% \begin{macrocode}
+ \AddToHook { begindocument/before } [ postnotes/mkbibendnote ]
+ {
+ \cs_set_nopar:Npn \blx@theendnote { \postnote }
+ \cs_set_nopar:Npn \blx@theendnotetext
+ { \blx@err@endnote \footnotetext }
+ }
+% \end{macrocode}
+% Auxiliary functions.
+%
+% \begin{macro}{\@@_biblatex_endrefcontext_local:}
+% Replicate the job of \cs{endrefcontext}, but with local effects,
+% restrained to the group of \cs{printpostnotes}.
+% \begin{macrocode}
+ \cs_new_protected:Npn \@@_biblatex_endrefcontext_local:
+ {
+ \togglefalse { blx@refcontext }
+ \tl_clear:N \blx@refcontext@labelprefix
+ \tl_clear:N \blx@refcontext@labelprefix@real
+ \tl_set:Nx \blx@refcontext@sortingtemplatename { \blx@sorting }
+ \tl_set:Nn \blx@refcontext@sortingnamekeytemplatename { global }
+ \tl_set:Nn \blx@refcontext@uniquenametemplatename { global }
+ \tl_set:Nn \blx@refcontext@labelalphanametemplatename { global }
+ \blx@edef@refcontext
+ {
+ \blx@refcontext@sortingtemplatename /
+ \blx@refcontext@sortingnamekeytemplatename /
+ /
+ \blx@refcontext@uniquenametemplatename /
+ \blx@refcontext@labelalphanametemplatename
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_biblatex_citereset_local:}
+% Replicate the job of \cs{citereset}, but with local effects, restrained to
+% the group of \cs{printpostnotes}.
+% \begin{macrocode}
+ \cs_new_protected:Npn \@@_biblatex_citereset_local:
+ {
+% \end{macrocode}
+% \noindent
+% {\em\scriptsize\verb|\global\cslet{blx@bsee@\the\c@refsection}\@empty|} \\
+% {\em\scriptsize\verb|\global\cslet{blx@fsee@\the\c@refsection}\@empty|}
+% \begin{macrocode}
+ \tl_clear:c { blx@bsee@ \int_use:N \c@refsection }
+ \tl_clear:c { blx@fsee@ \int_use:N \c@refsection }
+% \end{macrocode}
+% {\em\scriptsize\verb|\blx@ibidreset@force|}
+% \begin{macrocode}
+ \undef \blx@lastkey@text
+ \undef \blx@lastkey@foot
+% \end{macrocode}
+% {\em\scriptsize\verb|\blx@idemreset@force|}
+% \begin{macrocode}
+ \undef \blx@lasthash@text
+ \undef \blx@lasthash@foot
+% \end{macrocode}
+% {\em\scriptsize\verb|\blx@opcitreset@force|}
+% \begin{macrocode}
+ \clist_map_inline:Nn \blx@trackhash@text
+ { \csundef { blx@lastkey@text@ ##1 } }
+ \tl_clear:N \blx@trackhash@text
+ \clist_map_inline:Nn \blx@trackhash@foot
+ { \csundef { blx@lastkey@foot@ ##1 } }
+ \tl_clear:N \blx@trackhash@foot
+% \end{macrocode}
+% {\em\scriptsize\verb|\blx@loccitreset@force|}
+% \begin{macrocode}
+ \clist_map_inline:Nn \blx@trackkeys@text
+ { \csundef { blx@lastnote@text@ ##1 } }
+ \tl_clear:N \blx@trackkeys@text
+ \clist_map_inline:Nn \blx@trackkeys@foot
+ { \csundef { blx@lastnote@foot@ ##1 } }
+ \tl_clear:N \blx@trackkeys@foot
+% \end{macrocode}
+% {\em\scriptsize{}and all of them do:}
+% \begin{macrocode}
+ \cs_set_eq:NN \blx@lastmpfn \z@
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macrocode}
+ }
+% \end{macrocode}
+%
+% \pkg{biblatex}'s \texttt{refsections}, contrary to \texttt{refsegment}s and
+% \texttt{refcontext}s which are handled in the \LaTeX{} side of things (as
+% far as I can tell), need to go through \texttt{biber}, and must have correct
+% corresponding citation data written to the \file{.bcf} file. And the way
+% \cs{refsection} is implemented presumes each section is only ever begun once
+% (fair\dots{}), thus making it difficult to ``reopen'' it, or append new
+% citations to it later on, when the notes are printed. Given the complexity
+% of this machinery, it would be madness not to use \pkg{biblatex}'s
+% infrastructure directly, and try to ``emulate'' it. The start of a
+% \texttt{refsection} must be registered on the \file{.bcf} file, and this is
+% done by \cs{refsection} (and its auxiliary functions). However, a number of
+% its characteristics make things particularly difficult for the purpose at
+% hand: i) it unconditionally sets a label for the section which, of course,
+% cannot be done twice; and, critically, ii) the optional argument of the
+% environment (which receives the \meta{resources}) is used to set a local
+% assignment to \cs{blx@bibfiles}, based on which the relevant information is
+% written to the \file{.bcf} file, and when the group closes the information
+% is gone. My best attempt is below (excluded from the package) but it is not
+% good. It feels a wrong approach to ``go around'' the intended use of
+% \cs{refsection} so much, and it can't handle at all its optional argument,
+% for the reasons above. It's also incomplete, since it does not handle
+% restoring \cs{l_@@_biblatex_orig_refsection_tl}.
+%
+% \begin{macrocode}
+%<*gobble>
+\AddToHook { package/biblatex/after }
+ {
+ \tl_new:N \l_@@_biblatex_orig_refsection_tl
+ \tl_new:N \g_@@_biblatex_prev_refsection_tl
+ \AddToHook { postnotes/print/begin } [ postnotes ]
+ {
+ \tl_set:Nx \l_@@_biblatex_orig_refsection_tl
+ { \int_use:N \c@refsection }
+ \tl_gset:Nx \g_@@_biblatex_prev_refsection_tl
+ \l_@@_biblatex_orig_refsection_tl
+ }
+ \AddToHook { postnotes/print/eachnote } [ postnotes ]
+ {
+ \@@_prop_get:nnN { \l_@@_print_note_id_tl }
+ { biblatex@refsection } \l_@@_biblatex_restore_tl
+ \tl_if_eq:NNF
+ \l_@@_biblatex_restore_tl
+ \g_@@_biblatex_prev_refsection_tl
+ {
+ \int_set:Nn \c@blx@maxsection
+ { \l_@@_biblatex_restore_tl - 1 }
+ \tl_gset_eq:NN \g_@@_biblatex_prev_refsection_tl
+ \l_@@_biblatex_restore_tl
+ \group_begin:
+ \cs_set_eq:NN \label \use_none:n
+ \cs_set_eq:NN \blx@info \use_none:n
+ \blx@endrefsection
+ \refsection
+ \group_end:
+ }
+ }
+ }
+%</gobble>
+% \end{macrocode}
+%
+%
+% \subsection*{\pkg{zref-user}}
+%
+% \begin{macro}{\l_@@_note_zlabel_tl}
+% Even though the \opt{zlabel} option is provided only when \pkg{zref-user}
+% is loaded, \cs{l_@@_note_zlabel_tl} must be unconditionally defined, since
+% it is presumed to exist by \cs{@@_set_user_labels:}.
+% \begin{macrocode}
+\tl_new:N \l_@@_note_zlabel_tl
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macrocode}
+\AddToHook { package/zref-user/after }
+ {
+% \end{macrocode}
+% Provide \opt{zlabel} option.
+% \begin{macrocode}
+ \keys_define:nn { postnotes/note }
+ {
+ zlabel .tl_set:N = \l_@@_note_zlabel_tl ,
+ zlabel .value_required:n = true ,
+ }
+% \end{macrocode}
+%
+% \begin{macro}[int]{\postnotezref}
+% Provide \cs{postnotezref}.
+% \begin{syntax}
+% \cs{postnotezref}\meta{*}\marg{label}
+% \end{syntax}
+% \begin{macrocode}
+ \NewDocumentCommand \postnotezref { s m }
+ { \@@_note_zref:nn {#1} {#2} }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_note_zref:nn}
+% The internal version of \cs{postnotezref}.
+% \begin{syntax}
+% \cs{@@_note_zref:nn} \Arg{star bool} \Arg{label}
+% \end{syntax}
+% \begin{macrocode}
+ \cs_new_protected:Npn \@@_note_zref:nn #1#2
+ {
+ \group_begin:
+ \@@_typeset_mark_wrapper:n
+ {
+ \bool_lazy_and:nnTF
+ { ! #1 }
+ { \l_@@_hyperlink_bool }
+ {
+ \hyperlink
+ { \zref@extractdefault {#2} { anchor } { } }
+ { \@@_make_mark:nnn { \zref{#2} } { } { } }
+ }
+ { \@@_make_mark:nnn { \zref{#2} } { } { } }
+ }
+ \group_end:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macrocode}
+ }
+% \end{macrocode}
+%
+%
+% \subsection*{\pkg{zref-clever}}
+%
+% \begin{macrocode}
+\AddToHook { package/zref-clever/after }
+ {
+ \zcsetup
+ {
+ countertype = { postnote = endnote } ,
+ countertype = { postnotetext = endnote } ,
+ }
+ \AddToHook { postnotes/print/begin } [ postnotes ]
+ { \zcsetup { counterresetby = { postnotetext = postnotesection } } }
+ }
+% \end{macrocode}
+%
+%
+% \subsection*{\pkg{amsmath}}
+%
+% \begin{macrocode}
+\AddToHook { package/amsmath/after }
+ {
+% \end{macrocode}
+% Testing for \cs{ifmeasuring@} is sufficient to get things right for the
+% measuring passes in math environments.
+% \begin{macrocode}
+ \AddToHook { postnotes/note/inhibit } [ postnotes ]
+ {
+ \legacy_if:nT { measuring@ }
+ {
+ \bool_set_true:N \l_@@_inhibit_note_bool
+ \bool_set_true:N \l_@@_print_plain_mark_bool
+ }
+ }
+% \end{macrocode}
+% However, the \cs{text} macro, defined by \pkg{amstext} (required by
+% \pkg{amsmath}), poses problems if its own. Despite my best efforts, I could
+% not salvage things from the use of \cs{mathchoice} and the redefinitions of
+% \cs{setcounter} and \cs{addtocounter} performed by \pkg{amstext}. Setting
+% \cs{l_@@_maybe_multi_bool} when \texttt{firstchoice@} is \texttt{false}
+% grants us a working situation for display style. But the use of
+% \cs{postnote} inside \cs{text} (and, if \pkg{amsmath} is loaded,
+% \cs{textnormal}, \cs{textup}, etc.) in inline math environments is not
+% supported. If a note really needs to be there, one can use the \opt{nomark}
+% option and \cs{postnoteref}. Things should work in text mode and in display
+% style.
+% \begin{macrocode}
+ \AddToHook { postnotes/note/begin } [ postnotes ]
+ {
+ \legacy_if:nF { firstchoice@ }
+ { \bool_set_true:N \l_@@_maybe_multi_bool }
+ }
+ }
+% \end{macrocode}
+%
+%
+% \subsection*{\pkg{csquotes}}
+%
+% \begin{macrocode}
+\AddToHook { package/csquotes/after }
+ {
+ \bool_new:N \l_@@_csquotes_measuring_bool
+ \BlockquoteDisable
+ { \bool_set_true:N \l_@@_csquotes_measuring_bool }
+ \AddToHook { postnotes/note/inhibit } [ postnotes ]
+ {
+ \bool_if:NT \l_@@_csquotes_measuring_bool
+ {
+ \bool_set_true:N \l_@@_inhibit_note_bool
+ \bool_set_true:N \l_@@_print_plain_mark_bool
+ }
+ }
+ }
+% \end{macrocode}
+%
+%
+% \subsection*{\pkg{tabularx}}
+%
+% For the identification of the trial passes in \pkg{tabularx}, see
+% \url{https://tex.stackexchange.com/a/640035} (including discussion in the
+% comments, thanks \contributor{David Carlisle}), and also
+% \url{https://tex.stackexchange.com/a/227155} and
+% \url{https://tex.stackexchange.com/a/352134}.
+%
+% \begin{macrocode}
+\AddToHook { package/tabularx/after }
+ {
+ \bool_new:N \l_@@_tabularx_inside_env_bool
+ \AddToHook { env/tabularx/begin } [ postnotes ]
+ {
+ \bool_set_true:N \l_@@_tabularx_inside_env_bool
+ \cs_set_eq:NN \@@_tabularx_saved_write:Nn \write
+ }
+ \AddToHook { postnotes/note/inhibit } [ postnotes ]
+ {
+ \bool_lazy_and:nnT
+ { \l_@@_tabularx_inside_env_bool }
+ { ! \cs_if_eq_p:NN \write \@@_tabularx_saved_write:Nn }
+ {
+ \bool_set_true:N \l_@@_inhibit_note_bool
+ \bool_set_true:N \l_@@_print_plain_mark_bool
+ }
+ }
+ }
+% \end{macrocode}
+%
+%
+% \subsection*{\pkg{tabularray}}
+%
+% I've tried, but I could not find any ``handle'' to distinguish in
+% \pkg{tabularray} a trial/measure pass from the final one. So we use
+% \cs{@@_verify_multipass:N} for it.
+%
+% \begin{macrocode}
+\AddToHook { package/tabularray/after }
+ {
+ \clist_map_inline:nn
+ { tblr , longtblr , talltblr , booktabs , longtabs , talltabs , +array }
+ {
+ \AddToHook { env/#1/begin } [ postnotes ]
+ { \bool_set_true:N \l_@@_maybe_multi_bool }
+ }
+ }
+% \end{macrocode}
+%
+%
+% \section{Languages}
+% \label{sec:languages}
+%
+% \begin{macro}[int]
+% {
+% \pntitle ,
+% \pnhdnotes ,
+% \pnhdtopage ,
+% \pnhdtopages ,
+% }
+% Set of language specific user variables. They are used in the default
+% value of the \opt{heading} option and in \cs{pnheaderdefault} which,
+% ultimately, is also used in the same place.
+% \begin{macrocode}
+\tl_new:N \pntitle
+\tl_new:N \pnhdnotes
+\tl_new:N \pnhdtopage
+\tl_new:N \pnhdtopages
+\tl_set:Nn \pntitle { Notes }
+\tl_set:Nn \pnhdnotes { Notes }
+\tl_set:Nn \pnhdtopage { to~page }
+\tl_set:Nn \pnhdtopages { to~pages }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\@@_define_language:nn}
+% Defines language specific values for \meta{postnote language} by storing a
+% set of assignments for the language specific variables in \meta{setup}.
+% \meta{postnote language} is an internal name, typically the ``main'' name
+% of the language, based on which we can set specific \pkg{babel} or
+% \pkg{polyglossia} languages or variants.
+% \begin{syntax}
+% \cs{@@_define_language:nn} \Arg{postnote language} \Arg{setup}
+% \end{syntax}
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_define_language:nn #1#2
+ {
+ \tl_new:c { g_@@_language_ #1 _tl }
+ \tl_gset:cn { g_@@_language_ #1 _tl } {#2}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% For \pkg{babel} we use the new hook system, it's clean, and avoids the
+% \cs{addto} pitfalls. The appropriate hook to use is
+% \texttt{babel/\meta{language}/beforeextras} so that users can override it
+% with a traditional
+% \texttt{\textbackslash{}addto\textbackslash{}extras\meta{language}}.
+%
+% Note that, for \pkg{babel}, the captions are currently handled in two
+% different ways -- the ``old way'' and the ``new way'' -- and which of them
+% is used depends on the language. Most still use the ``old way'', but the
+% problem is that it is not universal. And the ``new way'' uses a different
+% naming scheme -- \texttt{\textbackslash{}\meta{language}\meta{caption}},
+% which is meant to be set with \cs{setlocalecaption}, and not suitable for
+% our needs. The \texttt{\textbackslash{}extras\meta{language}} macros are
+% meant for ``arbitrary'' code to be run when the language is selected, which
+% is what we want. The captions used to work in the same way, but no longer
+% for languages which use the ``new way''.
+%
+% Note also that there seems to exist some qualms about \pkg{babel}'s
+% \cs{addto}. A number of packages define their own versions of it. Do so at
+% least \pkg{varioref} (probably the original), \pkg{backref}, and
+% \pkg{cleveref}. The latter comments that \cs{addto} is ``flawed''.
+% \pkg{babel} itself comments the definition recognizing that there is an
+% ``inconsistency'': depending on the case, the operation will be either local
+% or global. This is documented in the manual, which explains this
+% inconsistent behavior is preserved for backward compatibility, and
+% recommends \pkg{etoolbox}'s facilities if available. \pkg{polyglossia} also
+% recommends \pkg{etoolbox}'s \cs{gappto}. All in all, if there's need to use
+% the traditional way instead of the new hooks, just rely on \texttt{expl3}
+% and use \cs{tl_gput_right:Nn}.
+%
+% \begin{macro}{\@@_set_babel_language:nn}
+% Sets \meta{babel language} to execute the setup defined by
+% \cs{@@_define_language:nn} for \meta{postnote language} at the
+% \texttt{babel/\meta{language}/beforeextras} hook.
+% \begin{syntax}
+% \cs{@@_set_babel_language:nn} \Arg{babel language} \Arg{postnote language}
+% \end{syntax}
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_set_babel_language:nn #1#2
+ {
+ \ActivateGenericHook { babel/#1/beforeextras }
+ \exp_args:Nnv \AddToHook { babel/#1/beforeextras }
+ { g_@@_language_ #2 _tl }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \pkg{polyglossia} uses a similar set of macros for setting up languages as
+% \pkg{babel} does. However, the
+% \texttt{\textbackslash{}blockextras@\meta{language}} macros are
+% unfortunately internal (despite what the manual says, that's what the code
+% does), thus requiring \cs{makeatletter}/\cs{makeatother} for user
+% configuration, which would be an inconvenience. On the other hand,
+% \pkg{polyglossia}'s \texttt{\textbackslash{}captions\meta{language}} works
+% as in \pkg{babel}'s ``old way'', meaning it is just a ``hook'' to which we
+% can append some code. So we use
+% \texttt{\textbackslash{}captions\meta{language}} for \pkg{polyglossia}.
+% Things may complicate here if there's need to set up different values for
+% different language variants, since the hooks available are all necessarily
+% internal, but I doubt we'll ever need variants for these simple strings.
+%
+% \begin{macro}{\@@_set_polyglossia_language:nn}
+% Sets \meta{polyglossia language} to execute the setup defined by
+% \cs{@@_define_language:nn} for \meta{postnote language} at the
+% \pkg{polyglossia} \texttt{\textbackslash{}captions\meta{language}} hook.
+% \begin{syntax}
+% \cs{@@_set_polyglossia_language:nn} \Arg{polyglossia language}
+% ~~\Arg{postnote language}
+% \end{syntax}
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_set_polyglossia_language:nn #1#2
+ {
+ \AddToHook { package/polyglossia/after }
+ {
+ \exp_args:Nnv \csgappto { captions #1 }
+ { g_@@_language_ #2 _tl }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \subsection*{English}
+%
+% \begin{macrocode}
+\@@_define_language:nn { english }
+ {
+ \tl_set:Nn \pntitle { Notes }
+ \tl_set:Nn \pnhdnotes { Notes }
+ \tl_set:Nn \pnhdtopage { to~page }
+ \tl_set:Nn \pnhdtopages { to~pages }
+ }
+\@@_set_babel_language:nn { english } { english }
+\@@_set_babel_language:nn { british } { english }
+\@@_set_babel_language:nn { american } { english }
+\@@_set_babel_language:nn { canadian } { english }
+\@@_set_babel_language:nn { australian } { english }
+\@@_set_babel_language:nn { newzealand } { english }
+\@@_set_babel_language:nn { UKenglish } { english }
+\@@_set_babel_language:nn { USenglish } { english }
+\@@_set_polyglossia_language:nn { english } { english }
+% \end{macrocode}
+%
+%
+% \subsection*{Portuguese}
+%
+% \begin{macrocode}
+\@@_define_language:nn { portuguese }
+ {
+ \tl_set:Nn \pntitle { Notas }
+ \tl_set:Nn \pnhdnotes { Notas }
+ \tl_set:Nn \pnhdtopage { da~página }
+ \tl_set:Nn \pnhdtopages { das~páginas }
+ }
+\@@_set_babel_language:nn { portuguese } { portuguese }
+\@@_set_babel_language:nn { brazilian } { portuguese }
+\@@_set_babel_language:nn { portuges } { portuguese }
+\@@_set_babel_language:nn { brazil } { portuguese }
+\@@_set_polyglossia_language:nn { portuguese } { portuguese }
+% \end{macrocode}
+%
+%
+% \begin{macrocode}
+%</package>
+% \end{macrocode}
+%
+%
+% \PrintIndex
+%
+%