% \iffalse meta-comment % %% File: latex-lab-footnotes.dtx % Copyright (C) 2022-2023 The LaTeX Project % % 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 % % % The development version of the bundle can be found below % % https://github.com/latex3/latex2e/required/latex-lab % % for those people who are interested or want to report an issue. % \def\ltlabfootnotedate{2023-09-04} \def\ltlabfootnoteversion{0.8c} %<*driver> \documentclass{l3doc} \EnableCrossrefs \CodelineIndex \begin{document} \DocInput{latex-lab-footnotes.dtx} \end{document} % % % \fi % % % \title{The \texttt{latex-lab-footnotes} code\thanks{}} % \author{Frank Mittelbach, \LaTeX{} Project} % % \maketitle % % \newcommand\fmi[1]{\begin{quote} TODO: \itshape #1\end{quote}} % \newcommand\NEW[1]{\marginpar{\mbox{}\hfill\fbox{New: #1}}} % \providecommand\class[1]{\texttt{#1.cls}} % \providecommand\pkg[1]{\texttt{#1}} % % \providecommand\hook[1]{\texttt{#1\DescribeHook[noprint]{#1}}} % \providecommand\socket[1]{\texttt{#1\DescribeSocket[noprint]{#1}}} % \providecommand\plug[1]{\texttt{#1\DescribePlug[noprint]{#1}}} % % \NewDocElement[printtype=\textit{socket},idxtype=socket,idxgroup=Sockets]{Socket}{socketdecl} % \NewDocElement[printtype=\textit{hook},idxtype=hook,idxgroup=Hooks]{Hook}{hookdecl} % \NewDocElement[printtype=\textit{plug},idxtype=plug,idxgroup=Plugs]{Plug}{plugdecl} % % \begin{abstract} % \emph{to be written} % \end{abstract} % % \tableofcontents % % % \section{Introduction} % % This code reimplements the footnote interfaces for \LaTeX{} % offering configurable methods for layout and functionality % adjustments that avoid overwriting each other when used in % classes as well as in packages (as far as possible --- obviously % some adjustments are mutually exclusive). This is achieved by % providing a larger number of hooks (for areas where different % packages/classes can easily coexist with their adjustments) and a % number of sockets to which only one class or package % can write to successfully (in case of multiple changes the % last one wins). The latter are for special functionality, e.g., % if footnote text is typeset as a single paragraph, it can't be configured % the same time to be typeset vertically with one footnote below % each other. % % The interfaces are set up to support tagged PDF, but in order % for this to work, all packages altering the footnote setup should % use the interfaces provided here and not do it through the % legacy methods (though there is some support for the latter as % well, but it will not work in all cases). % % \subsection{Configuration methods} % % Historically, the footnote setup in \LaTeX{} was done by % providing definitions for \cs{@makefnmark} (format the footnote % mark in running text and in front of the footnote text) and % \cs{@makefntext} (formatting the footnote text and placing a mark % in front of it). % % There was a default definition for \cs{@makefnmark} in the format % that was used by most document classes, % but \cs{@makefntext} had to be defined in the class itself because % the format didn't provide a default. As a result you will find % definitions for the latter in all document classes and definitions % for \cs{@makefnmark} only in very few. % % Furthermore, to enable special footnote layouts or provide % additional functionality a few packages (and a few classes) % overwrote other internal commands of \LaTeX's footnote % mechanism. The commands affected in this way are mainly % \cs{@footnotemark} and \cs{@footnotetext}. These overwrites could % not be used in combination, so either the packages/classes had to % be aware of being loaded together (which they sometimes did or % tried to) or they would fail by overwriting each other % unconditionally. % % The present rewrite is an attempt to improve this situation, but % of course, it will only work if all packages/classes make use of % the new interfaces. Fortunately, the number of problematical % packages altering these internal commands are fairly small so % arranging for updates is a realistic goal --- to achieve properly % tagged PDF it is a requirement. % % % % \section{Sockets and hooks} % % We use sockets for those parts that can be controlled only by one % package or by the kernel and hooks for places where it may be % possible that several packages or the document class adds code % (typically declarations such as font changes, etc.). % % Note that sockets are of interest only to very % few specialized packages, mainly \pkg{footmisc}, and packages % providing similar functionality---the current documentation is % therefore fairly sketchy. % % In contrast the hooks are of interest to many classes to provide % their layout alterations in a way that it works smoothly with % other packages handling aspects of footnote formatting. % % % \subsection{Formatting the mark in the main text} % % This implements formatting the mark\footnote{Like this one.} and % its relation to surrounding text, e.g., if several marks appear % in the same place, etc. % % % \subsubsection{Sockets} % % None: everything is implemented through a single definition for % \cs{@footnotemark} that offers a number of hooks that can be used % by packages to implement handling of multiple marks and the % formatting of marks. % % % \subsubsection{Hooks for formatting the footnote mark in text} % % The hooks to customize the marks in the text are the following: % \begin{description} % \item[\hook{fnmark/before}] % % \DescribeHook[noprint]{fnmark/before} % % Executed at the very beginning of \cs{footnotemark}. Currently % there are two packages (\pkg{bibarts} and \pkg{chextras}) that % prepend material at this point (not necessarily correctly, e.g., % they do not all check that they are in horizontal mode). % % This hook is paired with hook \hook{fnmark/after}. % % \item[\hook{fnmark}] % % \DescribeHook[noprint]{fnmark} % % Executed in horizontal mode and after the current space factor % has been saved away for reuse. This is where currently code for multiple % marks does its preparation (as done by \pkg{footmisc} and % others). % % The hook is only executed in hmode, i.e., not if the mark is % generated in math --- maybe that means the multiple handling % should happen later? % % After the hook a \cs{nobreak} is executed, so any % ``material'' added in the hook is tied to the following mark % unless it contains its own permissible penalty. % % \item[\hook{fnmark/begin}] % % \DescribeHook[noprint]{fnmark/begin} % % This hook is executed directly in front of the typeset mark. % This is the place where \pkg{hyperref} would have added % part of its code, i.e., after the \cs{nobreak} mentioned above. % With the integration of hyperlinks in the tagging code % this hook may not be necessary at all. % % \item[\hook{fnmark/end}] % % \DescribeHook[noprint]{fnmark/end} % % This hook is executed directly after the typeset mark. It is % used by \pkg{memhfixc}, \pkg{scrlttr2}, and % \pkg{footmisc}. Used, for example, to implement support for % multiple marks in succession. % % It is \emph{not} a reversed hook. % % % \item[\hook{fnmark/after}] % % \DescribeHook[noprint]{fnmark/after} % % This hook is executed at the very end of the \cs{footnotemark} command. % % It is a reversed hook to pair with \hook{fnmark/before} % \end{description} % % % % % \subsubsection{Additional configuration possibilities} % % The actual formatting is done through \cs{@makefnmark} --- no % special customization support for now. % % % % \subsection{Formatting the footnote text} % % This implements the formatting of the footnote text the way it % appears at the bottom of the page (default case), or possibly % elsewhere, e.g. in the margin. % % \subsubsection{Sockets} % % To cater for different layout configurations there are four % sockets that can be set by a package or % class but there should be only one per document setting them, i.e., if two packages/classes set them they are mutually % incompatible (or rather the last one wins most likely). % These are: % \begin{description} % \item[\socket{fntext/process} (1 argument)] % % \DescribeSocket[noprint]{fntext/process} % % This socket receives all material that is to be processed (or % stored) including color protection code and what have you. % The \plug{default} executes \cs{insert}\cs{footins}. % % Available plugs are \plug{default}, \plug{side} (side notes), and \plug{mp} (minipage). % % % \item[\socket{fntext/make} (1 argument)] % % \DescribeSocket[noprint]{fntext/make} % % This socket receives the \meta{text} as given in \cs{footnote} % or \cs{footnotetext} in the document and adds formatting % instructions to it. % % The \plug{default} plug runs \cs{@makefntext} which contains % various hooks for customization. For most scenarios this is % sufficient. However, when running all footnotes as a single % paragraph at the bottom, then each footnote needs to be % prepared prior to storing it with \cs{insert} and this socket % allows running extra code to do that. % % Available plugs are \plug{default} and \plug{para}. % % \item[\socket{fntext/begin} (no argument)] % % \DescribeSocket[noprint]{fntext/begin} % % The socket is executed near the start of the % argument for the \socket{fntext/make} socket. % By \plug{default} it adds a strut to the footnote % material so that consecutive footnotes are properly spaced % vertically. In some use cases this is not appropriate (e.g., % when running all footnotes as a single paragraph) and so with % this socket one can cancel the action or do something else % instead. % % Available plugs are \plug{default} and \plug{noop}. % % % \item[\socket{fntext/end} (no argument)] % % \DescribeSocket[noprint]{fntext/end} % % This socket is executed at the very end of the argument passed % to socket \socket{fntext/make}. By \plug{default} it % adds a final strut as long as we are still in horizontal mode % (i.e., processing the footnote text paragraph). When running % several footnotes in one paragraph some additional material % (some horizontal glue) needs adding at this point which is done % with the plug \plug{para}. % % Available plugs are \plug{default}, \plug{para}, and % \plug{noop}. % \end{description} % % % All standard plugs for the socket \socket{fntext/make} run % \cs{@makefntext} and this command contains two further % sockets (unless it is overwritten by a legacy class): % \begin{description} % \item[\socket{fntext/mark} (0 arguments)] % % \DescribeSocket[noprint]{fntext/mark} % % This socket has no input arguments but uses \cs{@makefnmark} to % typeset the mark in front of the footnote text. Its % \plug{default} uses code that examines the value of % \cs{footnotemargin} and based on its setting typeset the mark % in different ways: % \begin{itemize} % \item positive: typeset the mark in a box of that size % \item zero: use \cs{llap} around the mark % \item negative: use \cs{llap} but with a box of the given size % negated inside % \item \texttt{-}\cs{maxdimen}: just use \cs{@makefnmark} % \end{itemize} % For most cases this would be flexible enough, but if not then a % class can define its own plug to specify the placement of the mark. % % Available plugs are \plug{default} and \plug{noop} (no mark is produced). % % % \item[\socket{fntext/text} (1 argument)] % % \DescribeSocket[noprint]{fntext/text} % % This socket manages the formatting of the footnote text % (presented as an argument) once the mark has been typeset. In % all cases we can think of this formatting is better configured % via the available hooks described below, so the \plug{default} % just grabs the argument and processes it without any other % action. It is really only there to allow for some fancy stuff % that some design comes up with. % % Available plugs are \plug{identity} (default) and \plug{noop}. % % \end{description} % % % The above configuration points are sufficient to implement all % commonly used footnote layouts assuming L-R typesetting. For R-L % typesetting they or may or may not need some extension (though % that is not clear right now). % % % % \subsubsection{Hooks for formatting the footnote text} % % \begin{description} % \item[\hook{fntext/before}] % % \DescribeHook[noprint]{fntext/before} % % Executed at the very beginning of \cs{footnotetext}. Currently % there is one package (\pkg{linguex}) that % prepends material at this point. % % This hook is paired with hook \hook{fnmark/after}. % % \item[\hook{fntext}] % % \DescribeHook[noprint]{fntext} % % Executed at the beginning of the material passed to the first % configuration point. Typically used to set any baseline % stretch for the footnote text, e.g., by \pkg{setspace}, % \pkg{footmisc}, \class{uathesis} and others. Could be done in a % later hook but is a bit more efficient here. % % After the hook has run, the font is established, i.e., it can't % be used to set a different font size. % % \item[\hook{fntext/para}] % % \DescribeHook[noprint]{fntext/para} % % After the font is set (after the previous hook), some default % paragraph parameters % are set up % including \cs{interlinepenalty}, \cs{hsize}, \cs{parindent} and % a number of others, as some of them depend on the font % size. Then the \hook{fntext/para} is run which can overwrite % the default. If one wants to % change the font size, it is probably necessary to reset these % other parameters too, e.g., \cs{parindent}, which can be done % here. % % Note: the socket \socket{fntext/make} normally % runs the command \cs{@makefntext} or some code that eventually % runs this command, and this then produces the footnote mark in % front of the formatted footnote text. In % front of both the mark and the footnote text some classes have % placed paragraph parameter adjustments in their redefinition of % \cs{@makefntext}. However, there is no need to place it there % it could equally well go into the \hook{fntext/para} hook. We % therefore do not provide another hook at this other point. % % \item[\hook{fntext/begin} \& \hook{fntext/end}] % % \DescribeHook[noprint]{fntext/begin} % \DescribeHook[noprint]{fntext/end} % % The footnote text itself is surrounded by the hooks % \hook{fntext/begin} and \hook{fntext/end}. The two hooks are % not paired as they are typically used independently. % % \item[\hook{fntext/after}] % % \DescribeHook[noprint]{fntext/after} % % At the very end of \cs{footnotetext} we execute the hook % \hook{fntext/after} which is a reversed hook paired with % \hook{fntext/before}. Some packages, e.g., \pkg{linguex}, have % code in that position. % % \end{description} % % % % % \subsubsection{Additional configuration possibilities} % % The formatting of the footnote mark in front of the footnote % text is influenced by the setting of the dimen parameter % \cs{footnotemargin}. By default its value is 1.8em in the current % text font (or \texttt{-}\cs{maxdimen} when the para option is % chosen). The following rules apply: % \begin{itemize} % \item % % If it has the value \texttt{-}\cs{maxdimen} then the mark is % generated by \cs{@makefnmark}. % % \item % % Otherwise, if the value is % negative then the mark is placed into an \cs{llap} left aligned % in a box of size \texttt{-}\cs{footnotemargin}. % % \item % % If the value is zero an \cs{llap} is used without an inner box. % % \item % % If the value is greater zero (but less than \cs{maxdimen}) the % mark is placed right aligned into a box of size % \cs{footnotemargin}. % % \item % % The value \cs{maxdimen} is used as a marker to indicate that % no value was given and that the default should be used, % i.e. 1.8em or \texttt{-}\cs{maxdimen} depending on the chosen % option. % \end{itemize} % % % \section{Tagging and hyperlinking support} % % \fmi{this section needs work (and probably csname changes)} % % Footnotes consist of a \emph{footnotemark} (short: mark) that is typically placed in the text % as a superscript number like this\footnotemark[1], and a \emph{footnotetext} % (short: note) that is placed at the bottom of the page. % The \emph{footnotetext} normally repeats at the begin the mark as a visual clue. % % Tagging (and hyperlinking) has to connect the mark with the note. % For the tagging code, we assume that every mark has exactly one associated note, % and that every note is associated to at least one mark % and can have more associated marks. % % The mark doesn't need to be visible, e.g. the typesetted % mark\textsuperscript{1--3} denotes three marks, where the second is invisible. % Tagging should produce here probably three \texttt{Lbl} structures % (one without content), and an artifact for the range marker. % If such a range is used, links can only point to the notes 1 and 3 and % one has to suppress the linking for the second mark. % This means that links and tagging are also related % to the actual formatting of the footnote mark. % In the following this problem is mostly ignored for now, but % should not be forgotten and handled later. % % \subsection{Technical details for the tagging} % % The following sockets are set up for kernel use, when doing tagging: % \begin{description} % \item[\socket{tagsupport/fnmark} (1 argument)] % % \DescribeSocket[noprint]{tagsupport/fnmark} % % \fmi{describe and decide on names} % % % \item[\socket{tagsupport/fntext/begin} (no argument)] % % \DescribeSocket[noprint]{tagsupport/fntext/begin} % % % \item[\socket{tagsupport/fntext/end} (no argument)] % % \DescribeSocket[noprint]{tagsupport/fntext/end} % % % \item[\socket{tagsupport/fntext/mark} (1 argument)] % % \DescribeSocket[noprint]{tagsupport/fntext/mark} % % % \item[\socket{tagsupport/fntext/text} (1 argument)] % % \DescribeSocket[noprint]{tagsupport/fntext/text} % % % \end{description} % % % The \emph{footnotemark} should create a \texttt{/Lbl} structure\footnote{to make it easier % to identify the role we use \texttt{/footnotemark} which we rolemap to \texttt{/Lbl}} that should contain a \texttt{/Ref} entry pointing % to the structure of the \emph{footnotetext}. % % The \emph{footnotetext} should create a \texttt{/FENote}\footnote{We tag it as \texttt{/footnote} and role map it.} % structure with a \texttt{/Ref} % entry pointing to the structures of \emph{all} marks related to the note. % The mark at the begin of the % note is in a \texttt{/Lbl}\footnote{We tag it as \texttt{/footnotelabel}.} % structure but has to fulfil no special requirements. % % Structure objects and the underlying properties used by the tagging % code are initialized when the structure is opened. This means that one can not % directly add data to a future structure % but as structure objects are written at the end of the document it is % possible to update \texttt{/Ref} entries in an end document hook. % % % So tagging has to solve two problems: % \begin{itemize} % \item the mark and the footnote text must be surrounded by the correct structure % and marked content commands. This is not trivial % as there are various layouts (bottom, marginpar, minipage) and the tagging % from the automatic paratagging must be taken into account if one want to avoid % faulty nesting. % % \item It must detect which marks are related to which notes % so that it can setup the \texttt{/Ref} cross-references. % \end{itemize} % % % \subsection{Requirements for links} % % Links should go from the mark to the note. Sometimes it has been requested % that links go back too, but as there % can be more than one mark connected to a note it is not clear how to decide to which mark it should go. % Using the keys from the PDF viewer to go back is normally better. % % Links are closely related to the references stored in the \texttt{/Ref} % entry of a mark and so are handled in the code together with them. % But there are subtle technical differences to take care of % as links and destinations are whatsits and so must be created at the correct time. % % It should be possible to suppress the links both globally and locally.\footnote{ % Currently hyperref only offers the option to suppress the % footnote links globally % with the option \texttt{hyperfootnotes=false}. To suppress them locally % only the \texttt{NoHyper} environment is provided.} % % % \subsection{The algorithmus to connect marks and notes} % % % The connection is made by comparing the value of \cs{@thefnmark}. % % The standard mark commands (\cs{footnotemark} and \cs{footnote}) % store the current value of \cs{@thefnmark} % with their own structure number as a key in a property. % % A following \cs{footnotetext} compares its own \cs{@thefnmark} with the values in % the prop. If there is a match it stores the structure numbers and removes the entries % from the properties (so in a normal document the property will never contain more than % a few entries). % % This works well as long as the \cs{footnotemark} commands are issued before the \cs{footnotetext} and % as long as nothing unusual is done to \cs{@thefnmark}. % It also works if a document uses more than one footnote series as long as they have distinct numbering % systems, but in case a distinction is needed it is possible to define % a new class with its own data structure and to switch locally to use this % class. The following three commands are used for this. % % The default class uses the name \texttt{default} % % \begin{function}{\fnote_class_new:nn} % \begin{syntax} % \cs{fnote_class_new:nn}\Arg{name}\Arg{key/value option} % \end{syntax} % This declaration sets up the needed data structure. Currently this only % consists of a property list which is used to store and manage the mark values. % There are no options yet. % \end{function} % % \begin{function}{\fnote_mark_gput:nn,\fnote_mark_gput:no,\fnote_mark_gput:oo} % \begin{syntax} % \cs{fnote_mark_gput:nn}\Arg{mark}\Arg{class name} % \end{syntax} % This command stores the current structure number as key and the \meta{mark} as % value in the property list associated with the \meta{class name}. % \end{function} % % \begin{function}{\fnote_mark_gpop_all:nnN} % \begin{syntax} % \cs{fnote_mark_gpop_all:nnN}\Arg{mark}\Arg{class name}\meta{sequence} % \end{syntax} % This command stores all the keys/structure numbers whose value in the % property list for \meta{class name} are equal to \meta{mark} % into the sequence \meta{sequence} and then removes them from the property list. % The content of the sequence can then be % used to create link targets and references. % \end{function} % % % \subsubsection{\cs{footref}} % % \cs{footref} use internally the same command to set the mark as \cs{footnotemark}, it only % defines \cs{@thefnmark} differently. This \cs{@thefnmark} is not suitable for the method described % above, as it contains a reference command it can't be used to match a note, also \cs{footref} can % be used after the note has already been set. \cs{footref} disables therefore the automatic detection. % % Instead the \cs{label} command is % extended in the \cs{footnotetext} command to also store the structure number and \cs{footref} retrieves this % number to setup the reference and the link. % % The structure related to the \cs{footref} is added to the end of the \texttt{/Ref} array of the note and so the % \texttt{/Ref} array doesn't necessarly reflect the order of the marks in the document. It would probably % be possible to change this, but it is not clear if it actually matters and so it worth the additional coding % and processing. % % \subsubsection{\cs{footnotemark} after \cs{footnotetext}} % % The automatic detection doesn't work if a \cs{footnotemark} is issued after % the \cs{footnotetext} it refers to. There will be no error, but neither the link nor % the \texttt{/Ref} will connect both. % % The simple way to handle this is to use a label and \cs{footref}: % % \begin{verbatim} % \footnotetext{\label{fn:a}text} ... \footref{fn:a} % \end{verbatim} % % An alternative would be to extend the syntax of \cs{footnotemark} and % \cs{footnotetext} to allow to add a label which can then be used. % For example % % \begin{verbatim} % \footnotetext[label=fn:a]{text} ... \footnotemark[label=fn:a] % \end{verbatim} % % As both have already an optional argument, that requires the optional argument extension. % % % \subsection{Links} % % The structure numbers detected for the \texttt{/Ref} are also used for links: % even if tagging is not activated the tagging commands are defined through % the \pkg{tagpdf-base} package % and the structure commands increase the structure counter and this info can be used. % % A \cs{footnotetext} creates a bunch of destinations (in most cases this sums up to % two destinations): one for every structure number in the \texttt{/Ref} (used as target % by the mark commands) and one for the structure number of the footnotetest itself % (used as target by \cs{footref}s commands). % % \subsection{Implementation details regarding tagging} % % \subsection{Handling the mark} % % The mark in the text is handled by assigning an appropriate % plug to the socket \socket{tagsupport/fnmark}. % It takes one argument, \cs{@makefnmark}, the % command which formats the mark, and surrounds it by link and tagging % commands. At the point where the socket is % executed, \cs{@thefnmark} has already been defined and can be used to % setup the reference detections. % % % \subsection{Handling the footnotetext} % % The main part is done by assigning a different plug to socket \socket{tagsupport/fntext/begin} % and \socket{tagsupport/fntext/end} % surrounding the footnote text. % These sockets are used to start and end the structure and % attempt to detect to which mark the note is related. % % The actual typesetting of the note text is done by % \cs{fnote_makefntext:n} (or its \LaTeXe{} name \cs{@makefntext}). In % the new implementation this contains two further kernel sockets for tagging: % \socket{tagsupport/fntext/mark} and % \socket{tagsupport/fntext/text}. They get plugs assigned that add the % tagging commands around note mark and note text. % % \subsection{Footnotes in minipages} % % In minipages the \cs{footnote} command uses a special marker % (small italic letters by default) and puts the % footnote text at the bottom of the box. The \cs{footnotemark} % command uses the standard footnote counter and marker (and so typically % creates a superscript number). % It is meant to be used with a \cs{footnotetext} \emph{outside} % the minipage to create a footnote mark which refers to a footnote text % at the bottom of the page. % This means to repeat a footnote marker in a minipage you should use the \cs{footref} command. % % Tagging works quite similar to normal footnotes if the new definition is used % and if the minipage code is changed to use the new configuration point. % The main problem here is currently the tagging of the minipage itself. % % \section{TODOs} % % \begin{itemize} % % \item Special formatting of footnote marks in the text, e.g. if ranges or commas are % used require special care as they should normally mark up such text as artifacts and % perhaps have to insert empty structures to represent an invisible mark. This must be coordinated % with the relevant packages and classes. % % \item manyfoot doesn't work correctly and must be analyzed. % % \item \pkg{memoir} is not supported at all and errors when the code tries to patch % \cs{@makefntext}. % \end{itemize} % % \emph{To be documented} % % % % % \MaybeStop{\setlength\IndexMin{200pt} \PrintIndex } % % % \section{The Implementation} % % All this is very rough and misses a lot of documentation. % % \begin{macrocode} %<*kernel> %<@@=fnote> % \end{macrocode} % % \subsection{File declaration} % \begin{macrocode} \ProvidesFile{latex-lab-footnotes.ltx} [\ltlabfootnotedate\space v\ltlabfootnoteversion\space changes to the footnote interfaces] % \end{macrocode} % % \subsection{code not fully handled yet} % \begin{macrocode} % % latex.ltx % not looked at yet % \@mpfootnotetext is probably no longer needed, or only to support other % classes and package. See below about the minipage code. % % \long\def\@mpfootnotetext#1{% % \global\setbox\@mpfootins\vbox{% % \unvbox\@mpfootins % \reset@font\footnotesize % \hsize\columnwidth % \@parboxrestore % \def\@currentcounter{mpfootnote}% % \protected@edef\@currentlabel % {\csname p@mpfootnote\endcsname\@thefnmark}% % \color@begingroup % \@makefntext{% % \rule\z@\footnotesep\ignorespaces#1\@finalstrut\strutbox}% % \par % \color@endgroup}} % ======== % used by the minipage footnote code. % % \def\@mpfn{footnote} % \def\thempfn{\thefootnote} % ========= % this perhaps need some configuration options. % %\def\@makefnmark{\hbox{\@textsuperscript{\normalfont\@thefnmark}}} % % ========= %% alterations not covered: % % ./arabtex/afoot.sty --- too different (and probably too old) % % ===== % alterations of footnotetext not covered: % % ./revtex4-1/revtex4-1.cls ./revtex/ltxutil.sty ./revtex/revtex4-2.cls ... (need analysis) % ./bigfoot/bigfoot.sty % % memoir needs checking too % % ===== % % use of kerns to mark h-mode positions (unit sp) % % 1 = CJK % 2 = CJK % 3 = multiple footnotes (footmisc, koma, eledmac, tufte, memoir, % parnotes, sidenotes) % 3 = outer kern in letter spacing (letterspace) % 3 = beginning of list (examdesign.cls) % 4 = CJK pigin % 5 = CJK ruby % 1-4 = polyglossia for korean % % \end{macrocode} %------------------------------------- % \begin{macrocode} \ExplSyntaxOn % \end{macrocode} % \subsection{Temporary variables} % \begin{macrocode} \prop_new:N \l_@@_tmpa_prop \tl_new:N \l_@@_tmpa_tl % \end{macrocode} % \subsection{Public variables} % % A footnote mark will store its structure number (key) and the % expanded \cs{@thefnmark} in this prop so % that a following note can retrieve this info % if needed. It is possible to use more than one footnote series (type) % if needed (if different footnotes/note use the same % numbering system). % If this command is changed an accompanying property must be created % \begin{NOTE}{UF} % TODO: interface to create the property.\\ % TODO: check and decide about the name of the tl % \end{NOTE} % \begin{macro}{\l_fnote_type_tl} % \begin{macrocode} \tl_new:N \l_fnote_type_tl \tl_set:Nn \l_fnote_type_tl {default} % \end{macrocode} % \end{macro} % It must be possible to suppress the hyperlinking, both locally % and globally. hyperref's hyperfootnotes option should set the boolean. % \begin{macro}{\l_fnote_link_bool} % \begin{macrocode} \bool_new:N \l_fnote_link_bool \bool_set_true:N \l_fnote_link_bool % \end{macrocode} % \end{macro} % A hyperlink should have an changeable link type. This can % be e.g. used to change the color or the border. % \begin{macro}{\l_fnote_link_type_tl} % \begin{macrocode} \tl_new:N \l_fnote_link_type_tl \tl_set:Nn \l_fnote_link_type_tl {link} % \end{macrocode} % \end{macro} % % \subsection{Internal variables} % % \begin{macro}{\l_@@_linktarget_tl} % This command stores the name of a linktarget/destination % when needed % \begin{macrocode} \tl_new:N \l_@@_linktarget_tl % \end{macrocode} % \end{macro} % \begin{macro}{\l_@@_currentlabel_tl} % This command is used to pass a label name around. % \begin{macrocode} \tl_new:N \l_@@_currentlabel_tl % \end{macrocode} % \end{macro} % \begin{macro}{\l_@@_currentrefs_seq} % This sequence stores the list of reference of a note % \begin{macrocode} \seq_new:N \l_@@_currentrefs_seq % \end{macrocode} % \end{macro} % % The connection between the mark(s) in the text and the note % is either deduced automatically or done through an label. % The default is automatic, but we must be able to suppress it. For this we use a boolean. % \begin{macro}{\l_@@_autodetect_bool} % \begin{macrocode} \bool_new:N \l_@@_autodetect_bool \bool_set_true:N \l_@@_autodetect_bool % \end{macrocode} % \end{macro} % This is used to pass the structure number of the note around, e.g. % to a label inside the note. % \begin{macrocode} \tl_new:N \l_@@_currentstruct_tl \tl_set:Nn \l_@@_currentstruct_tl {1} % \end{macrocode} % % % \subsection{Variants} % % \begin{macrocode} \cs_generate_variant:Nn \hook_gput_code:nnn{nne} \cs_generate_variant:Nn \tag_struct_use:n {e} % \end{macrocode} % % \subsection{Updating \cs{@thefnmark}} % \begin{macro}{\fnote_step_fnmark:nn} % This command updates \cs{@thefnmark}. The first argument % is an optional integer expression, the second a counter name. % If the optional argument is not given it steps the counter. % \begin{macrocode} \cs_new_protected:Npn \fnote_step_fnmark:nn #1#2 { \tl_if_novalue:nTF {#1} { \stepcounter {#2} \protected@xdef \@thefnmark { \use:c { the#2 } } } { \group_begin: % \end{macrocode} % Note that this is a local assignment even though \LaTeX{} % counters are normally globally changed. This is the way it was in % 2e and so far we haven't changed it. The alternative would be to % store the current value and restore it after \cs{@thefnmark} is % altered. % \begin{macrocode} \int_set:cn { c@#2 }{ #1 } \unrestored@protected@xdef \@thefnmark { \use:c { the#2 } } \group_end: } } % \end{macrocode} % \end{macro} % \begin{macro}{\fnote_set_fnmark:nn} % This is similar to the previous command, but it doesn't step the % counter but use the current value. % \begin{macrocode} \cs_new_protected:Npn \fnote_set_fnmark:nn #1#2 { \tl_if_novalue:nTF {#1} { \protected@xdef \@thefnmark { \use:c { the#2 } } } { \group_begin: \int_set:cn { c@#2 }{ #1 } \unrestored@protected@xdef \@thefnmark { \use:c { the#2 } } \group_end: } } % \end{macrocode} % \end{macro} % % \subsection{Hooks} % % \begin{hookdecl}{fnmark/before,fnmark/after, % fnmark, % fnmark/begin,fnmark/end} % Hooks in the footnotemark command. % \begin{macrocode} \NewMirroredHookPair{fnmark/before}{fnmark/after} \NewHook{fnmark} \NewHook{fnmark/begin} \NewHook{fnmark/end} % \end{macrocode} % \end{hookdecl} % % \begin{hookdecl}{fntext/before,fntext/after, % fntext, % fntext/begin,fntext/end,fntext/para} % Hooks in the footnotetext command: % \begin{macrocode} \NewMirroredHookPair{fntext/before}{fntext/after} \NewHook{fntext} \NewHook{fntext/para} \NewHook{fntext/begin} \NewHook{fntext/end} % \end{macrocode} % \end{hookdecl} % % \subsection{Debugging code} % the debugging code is just temporary % % For now we have debugging turned on by default % \begin{macrocode} \bool_new:N \g_fnote_debug_bool \bool_gset_true:N \g_fnote_debug_bool % \end{macrocode} % We log the hooks in the footnote mark command, but only once % \begin{macrocode} \cs_new_protected:Npn \@@_debug_footnotemark: { \bool_if:NT \g_fnote_debug_bool { \hook_log:n {fnmark/before} \hook_log:n {fnmark} \hook_log:n {fnmark/begin} \hook_log:n {fnmark/end} \hook_log:n {fnmark/after} \cs_gset_eq:NN \@@_debug_footnotemark: \prg_do_nothing: } } % \end{macrocode} % Similar for the footnotetext % \begin{macrocode} \cs_new_protected:Npn \@@_debug_footnotetext: { \bool_if:NT \g_fnote_debug_bool { \socket_log:n {fntext/process} \socket_log:n {fntext/make} \socket_log:n {fntext/begin} \socket_log:n {fntext/end} % \end{macrocode} % % \begin{macrocode} \socket_log:n {fntext/mark} \socket_log:n {fntext/text} % \end{macrocode} % % \begin{macrocode} \socket_log:n {tagsupport/fnmark} \socket_log:n {tagsupport/fntext/begin} \socket_log:n {tagsupport/fntext/end} \socket_log:n {tagsupport/fntext/mark} \socket_log:n {tagsupport/fntext/text} % \end{macrocode} % % \begin{macrocode} \hook_log:n {fntext/before} \hook_log:n {fntext} \hook_log:n {fntext/para} \hook_log:n {fntext/begin} \hook_log:n {fntext/end} \hook_log:n {fntext/after} % \end{macrocode} % Show the info only once (if at all). % \begin{macrocode} \cs_gset_eq:NN \@@_debug_footnotetext: \prg_do_nothing: } } % \end{macrocode} % % \subsection{The new \cs{@footnotemark} command} % \begin{macro}{\fnote_footnotemark:} % This is the main command which will replace \cs{@footnotemark}. % \begin{macrocode} \cs_new_protected:Npn \fnote_footnotemark: { \@@_debug_footnotemark: %------- % bibarts % chextras --- actually in the wrong place does an \unskip \hook_use:n {fnmark/before} %------- \leavevmode \ifhmode \edef\@x@sf{\the\spacefactor} %------- % bxjsja-minimal.def --- what they do could be done at ``bibarts'' % (a bit less efficient) % memhfixc.sty % footmisc.sty \hook_use:n {fnmark} %------- \nobreak \fi %------- % hyperref.sty \hook_use:n {fnmark/begin} %------- % \end{macrocode} % The kernel socket for tagging. It picks up \cs{@makefnmark} as its % argument and if tagging is not active it contains the \plug{identity} plug. % \begin{macrocode} \socket_use:nn {tagsupport/fnmark} \@makefnmark %------- % \end{macrocode} % If a footnote mark is placed by its own then it should finish by % executing the hook \hook{fnmark/end}, resetting the space factor, and % finishing with the hook \hook{fnmark/after}. However, in a complete % footnote these actions have to happen only after we have handled % the footnote text (e.g., by placing it into an \cs{insert}). In % such a situation \cs{_@@_footmark_finish:} below does nothing % and the action is carried out later. % \begin{macrocode} \@@_footnotemark_finish: } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_footnotemark_default_finish:,\@@_footnotemark_finish:} % The default definition for \cs{@@_footnotemark_finish:} is called \cs{@@_footnotemark_default_finish:} % \begin{macrocode} \cs_new_protected:Npn \@@_footnotemark_default_finish: { % hyperref.sty % memhfixc.sty --- could move fnmark/after % scrlttr2.cls --- could vanish if footmisc uses a hook % footmisc.sty \UseHook{fnmark/end} %------- \ifhmode \spacefactor \@x@sf \relax \fi % %------- \UseHook{fnmark/after} %------- } % \end{macrocode} % % \begin{macrocode} \cs_new_eq:NN \@@_footnotemark_finish: \@@_footnotemark_default_finish: % \end{macrocode} % \end{macro} % % \begin{socketdecl}{tagsupport/fnmark} % Not a public socket but reserved for tagging. By % default it contains \plug{identity} and is reassigned if tagging is active. % \begin{macrocode} \NewSocket{tagsupport/fnmark}{1} % \end{macrocode} % \end{socketdecl} % % \begin{macro}{\@footnotemark} % Here we provide the traditional \LaTeXe{} name in case it is directly used % in some legacy class. % \begin{macrocode} \cs_set_eq:NN \@footnotemark \fnote_footnotemark: % \end{macrocode} % \end{macro} % % % \subsection{The new \cs{@footnotetext} command} % % % \begin{macro}{\fnote_footnotetext:n} % \begin{macrocode} \cs_new_protected:Npn \fnote_footnotetext:n #1 { \@@_debug_footnotetext: %------- % ./linguex/linguex.sty \hook_use:n {fntext/before} %------- % \end{macrocode} % Execute a kernel socket for tagging. % \begin{macrocode} \socket_use:n {tagsupport/fntext/begin} % \end{macrocode} % % \begin{macrocode} \socket_use:nn {fntext/process} { %------- % resetting baselinestretch ... (could be done further down) % ./uafthesis/uafthesis.cls % ./setspace/setspace.sty % ./footmisc/footmisc.sty (normal) \hook_use:n {fntext} %------- \reset@font \footnotesize %------- % some classes use a different font size, e.g., % ./nrc/nrc1.cls ./nrc/nrc2.cls % but those could be done in fntext/para instead %------- % \end{macrocode} % In case of sidenotes the next settings are pointless, but as they % do not hurt (except for the \cs{hsize} setting) and are needed % for all other cases we make them here and overwrite them for side notes % \begin{macrocode} \interlinepenalty\interfootnotelinepenalty \splittopskip\footnotesep \splitmaxdepth \dp\strutbox \floatingpenalty \@MM \hsize\columnwidth \@parboxrestore \parindent 1em % typical default used in \@makefntext moved up here \def\@currentcounter{footnote} \protected@edef \@currentlabel { \p@footnote \@thefnmark } %------- % for altering para parameters ... % code for resphilosophica came earlier but it could go here. % Has the advantage that one can also overwrite \cs{@currentcounter} % and \cs{@currentlabel} is that is necessary. % % ./resphilosophica/resphilosophica.cls \hook_use:n {fntext/para} %------- \color@begingroup %------- % fnpara wants to replace \@makefntext{...} and para and side % option of footmisc etc too ... % so we make this a socket, because only one action can be active: %------- \socket_use:nn {fntext/make} { %------- % ./resphilosophica/resphilosophica.cls %------- \socket_use:n {fntext/begin}% %------- % bibarts % fnbreak.sty \hook_use:n {fntext/begin} %------- \ignorespaces #1 %------- % bibarts % fnbreak.sty \hook_use:n {fntext/end} %------- % \end{macrocode} % The socket code (by default adding a strut) has to come % \emph{after} everything added into the hook above. % \begin{macrocode} \socket_use:n {fntext/end} } \par \color@endgroup } %------- % \end{macrocode} % The corresponding kernel hook that ends the tagging structure if % tagging is active. % \begin{macrocode} \socket_use:n{tagsupport/fntext/end} %------- % ./linguex/linguex.sty \hook_use:n {fntext/after} %------- } % \end{macrocode} % \end{macro} % % \begin{socketdecl}{fntext/process} % % \begin{macrocode} \NewSocket {fntext/process}{1} \NewSocketPlug{fntext/process}{default}{ \insert\footins {#1} } \NewSocketPlug{fntext/process}{side} { \marginpar {#1} } % \end{macrocode} % % \begin{macrocode} \AssignSocketPlug{fntext/process}{default} % \end{macrocode} % \end{socketdecl} % % % % \begin{socketdecl}{fntext/make} % This socket receives the \meta{text} from the \cs{footnote} or % \cs{footnotetext} and formats it. % \begin{macrocode} \NewSocket {fntext/make}{1} \NewSocketPlug{fntext/make}{default}{ \@makefntext {#1} } % \end{macrocode} % When running several footnotes together as a paragraph some % additional work is necessary to unbox the individual footnotes % recursively (see \TeX{}book algorithm in appendix~D). % \begin{macrocode} \NewSocketPlug{fntext/make}{para} { \setbox\FN@tempboxa\hbox{\@makefntext{#1}}% \dp\FN@tempboxa\z@ \ht\FN@tempboxa \dimexpr\wd\FN@tempboxa *% \footnotebaselineskip /\columnwidth\relax \box\FN@tempboxa } % \end{macrocode} % % \begin{macrocode} \AssignSocketPlug{fntext/make}{default} % \end{macrocode} % \end{socketdecl} % % \begin{socketdecl}{fntext/begin} % By default adds a strut at the start of the footnote text. % \begin{macrocode} \NewSocket {fntext/begin}{0} \NewSocketPlug{fntext/begin}{default}{ \rule\z@\footnotesep } % \end{macrocode} % % \begin{macrocode} \AssignSocketPlug{fntext/begin}{default} % \end{macrocode} % \end{socketdecl} % % \begin{socketdecl}{fntext/end} % By default adds a strut at the end of the footnote text unless we % are no longer in hmode. % \begin{macrocode} \NewSocket {fntext/end}{0} \NewSocketPlug{fntext/end}{default}{ \@finalstrut\strutbox } % \end{macrocode} % When running several footnotes together as a paragraph some % additional glue has to be added between them. % \begin{macrocode} \NewSocketPlug{fntext/end}{para} {% \strut \penalty-10\relax \hskip\footglue } % \end{macrocode} % % \begin{macrocode} \AssignSocketPlug{fntext/end}{default} % \end{macrocode} % \end{socketdecl} % % \begin{socketdecl}{tagsupport/fntext/begin,tagsupport/fntext/end} % Kernel sockets for tagging. % \begin{macrocode} \NewSocket{tagsupport/fntext/begin}{0} \NewSocket{tagsupport/fntext/end}{0} % \end{macrocode} % \end{socketdecl} % % Provide the name \LaTeXe{} is used to and do this unconditionally % (no patching of class code if any). This means that if a class % provides it own definition that gets lost and if necessary needs to % be handled with firstaid (or updating of the class). % \begin{macrocode} \AddToHook{begindocument} { \cs_set_eq:NN \@footnotetext \fnote_footnotetext:n } % \end{macrocode} % % % % % \subsection{The new \cs{@makefntext} command} % % \cs{footnotemargin} is the logic implemented by footmisc. Perhaps we % don't want to do this like that in the kernel but for now I have % used this interface unchanged. % \begin{macrocode} \newdimen\footnotemargin \footnotemargin\maxdimen % no value given \AtBeginDocument { \ifdim \footnotemargin=\maxdimen \setlength\footnotemargin{1.8em} \fi } % \end{macrocode} % % % % % \begin{macro}{\fnote_makefntext:n} % \begin{macrocode} \cs_new_protected:Npn \fnote_makefntext:n #1 { % \end{macrocode} % Some classes in their redefinition for \cs{@makefntext} have % placed some paragraph parameters at this point, but those can % equally well go into the hook \hook{fntext/para}. We therefore do % not provide a further hook at this point. % \begin{macrocode} \noindent % \end{macrocode} % % \begin{macrocode} \socket_use:nn {tagsupport/fntext/mark} { \socket_use:n {fntext/mark} } \socket_use:nn {tagsupport/fntext/text} { \socket_use:nn {fntext/text}{#1} } } % \end{macrocode} % \end{macro} % % \begin{socketdecl}{fntext/mark} % A socket to typeset the mark at the start of a footnote. % \begin{macrocode} \NewSocket {fntext/mark}{0} % \end{macrocode} % The \plug{default} plug implements the logic introduced with the % \pkg{footmisc} package. % \begin{macrocode} \NewSocketPlug{fntext/mark}{default}{ \ifdim\footnotemargin>\z@ \hb@xt@ \footnotemargin{\hss\@makefnmark} \else \ifdim\footnotemargin=\z@ \llap{\@makefnmark} \else \ifdim\footnotemargin=-\maxdimen \@makefnmark \else \llap{\hb@xt@ -\footnotemargin{\@makefnmark\hss}} \fi \fi \fi } % \end{macrocode} % % \begin{macrocode} \AssignSocketPlug{fntext/mark}{default} % \end{macrocode} % \end{socketdecl} % % \begin{socketdecl}{fntext/text} % By default this socket does nothing special and simply processes % its argument as provided. % \begin{macrocode} \NewSocket {fntext/text}{1} % \end{macrocode} % \end{socketdecl} % % % % \begin{socketdecl}{tagsupport/fntext/mark,tagsupport/fntext/text} % Not a public socket but reserved for tagging. By % default it contains \plug{identity} and is reassigned if tagging is active. % \begin{macrocode} \NewSocket{tagsupport/fntext/mark}{1} \NewSocket{tagsupport/fntext/text}{1} % \end{macrocode} % \end{socketdecl} % % % % \subsubsection{Making documents use the new \cs{@makefntext}} % % If the definition for \cs{@makefntext} is that of the standard % classes then replace it with \cs{fnote_makefntext:n}, otherwise % try to patch the definition used in the class. % % Here is the definition the way it is in % \texttt{classes.dtx}. Notice that (for saving space) there is no % space after \texttt{em} to terminate the assignment. We need to % mimic that, otherwise a test would return false even if the % definition has not been modified. % % % \begin{macro}{\old@std@class@makefntext} % \begin{macrocode} \newcommand\old@std@class@makefntext[1]{% \parindent 1em% \noindent \hb@xt@1.8em{\hss\@makefnmark}#1} % \end{macrocode} % \end{macro} % % Here is the messy code for patching. Note that this is only there % to help classes along that aren't updated yet so it does some % minimal patching to hopefully add kernel configuration hooks in the % right place while otherwise leaving the legacy code alone. An % updated class would not redefine \cs{@makefntext} but simply add % appropriate code to the provided hooks. % % What it does is roughly the % following: It looks for a definition of \cs{@makefntext} of the form %\begin{verbatim} % {AAA \hbox BBB { CCC } DDD #1 EEE } %\end{verbatim} % where ``BBB'' is something like \texttt{to 1em} or similar. It then % replaces that with %\begin{verbatim} % {AAA \UseSocket{tagsupport/fntext/mark}{\hbox BBB { CCC }} DDD % \UseSocket{tagsupport/fntext/text}{#1} EEE } %\end{verbatim} % The patching is not very careful, i.e., it assumes there is only % one \verb=#1= in the replacement text and that the first \cs{hbox} found % is the right one to patch. But that is enough to cater for all % definitions of \cs{@makefntext} out there in the TL distribution. % % If \cs{hbox} is not found it tries the same looking for % \cs{hb@xt@} which is what some classes use and if that is not % found either it assume that this is a version that uses % \cs{@makefnmark} without surrounding it in a box and if that % fails it gives up with an \cs{ERROR} (which needs to get a proper definition). % \begin{macrocode} \tl_new:N \l_@@_patch_tl \cs_new_eq:NN \@@_tmp:w \ERROR \cs_new_protected:Npn \@@_patch: { \tl_set:No \l_@@_patch_tl { \@makefntext { \UseSocket{tagsupport/fntext/text}{##1} } } \tl_if_in:NnTF \l_@@_patch_tl { \hbox } { \cs_set_eq:NN \@@_tmp:w \@@_patch_hbox:w } { \tl_if_in:NnTF \l_@@_patch_tl { \hb@xt@ } { \cs_set_eq:NN \@@_tmp:w \@@_patch_hb@xt@:w } { \tl_if_in:NnTF \l_@@_patch_tl { \@makefnmark } { \cs_set_eq:NN \@@_tmp:w \@@_patch_@makefnmark:w } { \ERROR \cs_set_eq:NN \@@_tmp:w \exp_stop_f: } } } \tl_set:Nf \l_@@_patch_tl { \exp_after:wN \@@_tmp:w \l_@@_patch_tl } \cs_set:Npn \@@_tmp:w { \long \def \@makefntext ####1 } \exp_after:wN \@@_tmp:w \exp_after:wN { \l_@@_patch_tl } } % \end{macrocode} % % If \cs{@makefntext} contains \cs{hbox} then grab ``AAA'' as % \verb=#1= and ``BBB'' (up to the open \texttt{\{}) and return it as %\begin{verbatim} % AAA \@makefntext@processX { \hbox BBB } %\end{verbatim} % % \begin{macrocode} \cs_new:Npn \@@_patch_hbox:w #1 \hbox #2 # { \exp_stop_f: #1 \@makefntext@processX { \hbox #2 } } % \end{macrocode} % Same for the other cases. % \begin{macrocode} \cs_new:Npn \@@_patch_hb@xt@:w #1 \hb@xt@ #2 # { \exp_stop_f: #1 \@makefntext@processX { \hb@xt@ #2 } } \cs_new:Npn \@@_patch_@makefnmark:w #1 \@makefnmark { \exp_stop_f: #1 \@makefntext@processX { \use:n } { \@makefnmark } } % \end{macrocode} % % The code provided by Bruno above expects 2 arguments but we need a % different structure so this is a simple reshuffling. Would be % better if we can patch the right structure in directly, but I'm % not a patch person, so this is the simple way out for now: % % \begin{macrocode} \cs_new:Npn \@makefntext@processX #1#2{\UseSocket{tagsupport/fntext/mark}{#1{#2}}} % \end{macrocode} % % At \verb=\begin{document}= check if the current definition is % that of the standard classes and if so replace it by % \cs{fnote_makefntext:n} otherwise try and patch the definition % made by some class or package % using the approach above. % \begin{macrocode} \AddToHook{begindocument} { \cs_if_eq:NNTF \@makefntext \old@std@class@makefntext { \cs_set_eq:NN \@makefntext \fnote_makefntext:n } { \@@_patch: } } % possibly add the following to check for multiple \hbox in % the definition: % % \seq_set_split:NnV \l_@@_patch_seq { \hbox } \l_@@_patch_tl % \int_compare:nT { \seq_count:N \l_@@_patch_seq } > 2 \ERROR % % \end{macrocode} % % \subsection{Document-level commands} % % \begin{macro}{\footnotetext} % \begin{macrocode} \DeclareDocumentCommand\footnotetext {o+m} { \fnote_set_fnmark:nn {#1} \@mpfn \@footnotetext {#2} } % \end{macrocode} % \end{macro} % % % \begin{macro}{\footnote} % \begin{macrocode} \DeclareDocumentCommand\footnote {o+m} { \fnote_step_fnmark:nn {#1} \@mpfn \cs_set_eq:NN \@@_footnotemark_finish: \prg_do_nothing: \@footnotemark \cs_set_eq:NN \@@_footnotemark_finish: \@@_footnotemark_default_finish: \@footnotetext {#2} \@@_footnotemark_finish: } % \end{macrocode} % \end{macro} % % \begin{macro}{\footnotemark} % \begin{macrocode} \DeclareDocumentCommand\footnotemark {o} { \fnote_step_fnmark:nn {#1} { footnote } \@footnotemark } % \end{macrocode} % \end{macro} % \begin{macro}{\footref} % \cs{footref} used the starred \cs{ref} in \cs{@thefnmark} % as the linking is handled by the tagging code inside % the \cs{@footnotemark}. % \cs{footref} should not try to link to its related % note automatically but should instead use the label. % This is passed to \cs{@footnotemark} through % \cs{l__fnote_currentlabel_tl}. % % \begin{macrocode} \DeclareDocumentCommand\footref {m} { \begingroup \unrestored@protected@xdef\@thefnmark{\ref*{#1}}% \endgroup \bool_set_false:N \l_@@_autodetect_bool \tl_set:Nn \l_@@_currentlabel_tl {#1} \@footnotemark \bool_set_true:N \l_@@_autodetect_bool } % \end{macrocode} % \end{macro} % % % \subsection{Firstaid for packages and classes} % % \subsection{Kernel patches} % Tagging of footnotes in minipages require a change in the minipage commands % We define at first a local configuration command for minipage footnotes. % % \begin{macrocode} \NewSocketPlug{fntext/process}{mp} { \global\setbox\@mpfootins\vbox{% \unvbox\@mpfootins #1 } } % \end{macrocode} % % \subsubsection{\pkg{memoir}} % The \pkg{memoir} class redefines various internal commands to inject its % hooks and addtional code. The following reinstates the kernel command and % so probably breaks various options of \pkg{memoir}, but without the % changes it errors anyway. The \pkg{footmisc} package should be used to change % for example to para footnotes. % % \begin{macrocode} \AddToHook{class/memoir/before} { \let\new@std@class@makecol\@makecol } \AddToHook{class/memoir/after} { \cs_set_eq:NN \@footnotemark \fnote_footnotemark: \cs_set_eq:NN \@makefntext\old@std@class@makefntext \cs_set_eq:NN \@makecol\new@std@class@makecol } % \end{macrocode} % % \subsubsection{\pkg{setspace}} % % It should not overwrite it any longer but use a hook, so for now we % do just that here. % \begin{macrocode} \AddToHook{package/setspace/after} {\let \@footnotetext \fnote_footnotetext:n \AddToHook{fntext}[setspace]{\let\baselinestretch\setspace@singlespace}} % \end{macrocode} % % % \subsubsection{\pkg{hyperref}} % % hyperref has a hook which allows to disable its footnote % related patches. As we will handle links directly in the code % this is used. % % \begin{macrocode} \def\hyper@nopatch@footnote{} % \end{macrocode} % We use the hyperref commands for now for links. To avoid % to have to test for hyperref we provide dummies. % TODO consider to use specials to get similar spacing. % \begin{macrocode} \AtBeginDocument { \providecommand\hyper@linkstart{\@gobbletwo} \providecommand\hyper@linkend{\@empty} } % \end{macrocode} % % It must be possible to suppress the hyperlinking, both locally % and globally. hyperref should set the boolean \cs{l_fnote_link_bool}. % For now we test for the hyperref boolean (so it can be suppressed only globally). % \begin{macrocode} \AtBeginDocument { \@ifpackageloaded{hyperref} { \legacy_if:nF{Hy@hyperfootnotes}{\bool_set_false:N \l_fnote_link_bool} } { \bool_set_false:N \l_fnote_link_bool } } % \end{macrocode} % % \subsection{Tagging and hyperlink code} % \subsubsection{Rolemap for structure tags} % We use role-mapping to get more speaking names % in the PDF and so ease debugging. These names are already % provided by tagpdf directly. % % \subsubsection{Extending the label system} % For \cs{footref} and (perhaps later for labeled footnotes) % we must extend the label system. % Beside the normal values we also need the structure number of the note. % We use the inbuild label hook % At first we define a suitable attribute, it uses as value the structure % number of the note as stored in \cs{l__fnote_currentstruct_tl} % \begin{macrocode} \property_new:nnnn {fnote/struct}{now}{1}{\l_@@_currentstruct_tl} % \end{macrocode} % % We add a hook to the label hook. By default it does nothing % \begin{macro}{\@@_label_hook:e} % \begin{macrocode} \cs_new_protected:Npn \@@_label_hook:e #1 {} \AddToHookWithArguments{label}{ \@@_label_hook:e{#1}} % \end{macrocode} % \end{macro} % Inside a footnotetext we change the hook to store the structure number too. % The name of label is provided as argument in the label hook. % \begin{macrocode} \AddToHook{fntext/begin} { \cs_set_protected:Npn \@@_label_hook:e #1 { \property_record:ee {@@/#1} {fnote/struct} } } % \end{macrocode} % % \subsubsection{Storing and retrieving reference data} % To establish the connection between a mark and a note % the mark has to store its representation, and the % note has to analyse the stored representations to get % the structure numbers of its mark. This is done % with the public function to allow similar systems (e.g. % tabular notes, other footnote series) to make use of this. % % % \begin{macro}{\fnote_class_new:nn} % This sets up a new footnote type, the first argument % is the name, the second is meant for options. Currently % it does nothing at all. % It is not necessary to setup every footnote like % command as its own type! % % \begin{macrocode} \cs_new_protected:Npn \fnote_class_new:nn #1 #2 % #1 name, #2 options { \prop_new:c { g_@@_currentmarks_ #1 _prop } } \fnote_class_new:nn {default}{} % \end{macrocode} % \end{macro} % % % \begin{macro}{\fnote_mark_gput:nn} % This commands takes as argument the representation of the mark, % e.g., \cs{@thefnmark} and the type (typically default should work). % \begin{macrocode} \cs_new_protected:Npn \fnote_mark_gput:nn #1 #2 % #1 the representation of the mark, #2 type { \prop_gput:cen { g_@@_currentmarks_ #2 _prop } { \tag_get:n{struct_num} } { #1 } } \cs_generate_variant:Nn \fnote_mark_gput:nn {no,oo} % \end{macrocode} % \end{macro} % % \begin{macro}{\fnote_mark_gpop_all:nnN} % This commands takes as argument the representation of the mark % (e.g. the content of\cs{@thefnmark}), the class (typically |default| should work) % and a sequence into which every structure number in the property % is stored that has the same value as the mark. The sequence is cleared first. % \begin{macrocode} \cs_new_protected:Npn \fnote_mark_gpop_all:nnN #1 #2 #3 { \seq_clear:N #3 \prop_set_eq:Nc \l_@@_tmpa_prop { g_@@_currentmarks_ #2 _prop } \prop_map_inline:Nn \l_@@_tmpa_prop { \tl_if_eq:nnT {#1} { ##2 } { % \end{macrocode} % store the key (the structure number) in the seq % \begin{macrocode} \seq_put_right:Nn #3 { ##1 } % \end{macrocode} % remove entry as used from the global prop % \begin{macrocode} \prop_gremove:cn { g_@@_currentmarks_ #2 _prop } {##1} } } } \cs_generate_variant:Nn\fnote_mark_gpop_all:nnN {ooN} % \end{macrocode} % \end{macro} % % % % % \subsubsection{Enabling tagging and links for the mark command} % % % \begin{plugdecl}{FEMark} % % To handle the mark in the text, we define a special plug for % the socket \socket{tagsupport/fnmark} that receives % \cs{@makefntext} as its argument. At this time \cs{@thefnmark} % is already set. % % \begin{macrocode} \NewSocketPlug{tagsupport/fnmark}{FEMark} { % \end{macrocode} % End an open mc and start the structure. % \begin{macrocode} \tag_mc_end_push: \tag_struct_begin:n { tag=footnotemark } % \end{macrocode} % The associated note is either auto detected % or given by the user. % \begin{macrocode} \bool_if:NTF \l_@@_autodetect_bool { % \end{macrocode} % For the auto detecting we store the structure number % and \cs{@thefnmark} inside a prop and set % the target name of the link to the current structure number. % TODO: this should be usable for other footnote types % which means the name of the prop shouldn't be fix. % \begin{macrocode} \fnote_mark_gput:oo {\@thefnmark}{\l_fnote_type_tl} \tl_set:Ne \l_@@_linktarget_tl {footnote*.\tag_get:n{struct_num}} } % \end{macrocode} % If there is no autodetecting we need some id, % currently it is called \cs{l__fnote_currentlabel_tl}. % the Ref is set by looking at the label value. % We must also add the current structure number to the \ref of the FEnote. % Both must be delayed as we don't know if the objects of the FEnote and the mark % have already been created. % \begin{macrocode} { \hook_gput_code:nne {tagpdf/finish/before} {tagpdf/footnote} { \exp_not:N\fnote_gput_refs:ee { \tag_get:n{struct_num} } { \property_ref:ee{ @@/\l_@@_currentlabel_tl } {fnote/struct} } } % \end{macrocode} % in this case we set the name of the linktarget in the note % to the structure number of the text mark. % \begin{macrocode} \tl_set:Ne \l_@@_linktarget_tl {footnote*.\property_ref:ee {@@/\l_@@_currentlabel_tl} {fnote/struct}} } % \end{macrocode} % And now the actual content % \begin{macrocode} \tag_mc_begin:n{tag=Lbl} % \bool_if:NTF \l_fnote_link_bool { \exp_args:No \hyper@linkstart { \l_fnote_link_type_tl } { \l_@@_linktarget_tl } #1 \hyper@linkend } { #1 } \tag_mc_end: \tag_struct_end: \tag_mc_begin_pop:n{} } % \end{macrocode} % At last assign the plug: % \begin{macrocode} \AssignSocketPlug{tagsupport/fnmark}{FEMark} % \end{macrocode} % \end{plugdecl} % % % % % \subsubsection{The footnote text} % We need a public command to append values to the Ref keys % \begin{macro}{\@@_gput_ref:nn,\fnote_gput_refs:nn,\fnote_gput_refs:ee} % \begin{macrocode} \cs_new_protected:Npn \@@_gput_ref:nn #1 #2 %#1 the structure number receiving the ref #2 { \tag_if_active:T { \tag_struct_gput:nne {#1}{ref}{\tag_struct_object_ref:e { #2 }} } } \cs_new_protected:Npn \fnote_gput_refs:nn #1 #2 % pair of numbers { \@@_gput_ref:nn {#1}{#2} \@@_gput_ref:nn {#2}{#1} } \cs_generate_variant:Nn \fnote_gput_refs:nn {ee} % \end{macrocode} % \end{macro} % % \begin{macrocode} \tl_new:N \l_@@_dflt_struct_tl \tl_set:Nn \l_@@_dflt_struct_tl {1} % \end{macrocode} % kernel hooks for taggin % this sets the structure around the whole text % % % \begin{plugdecl}{FENote} % \begin{macrocode} \NewSocketPlug{tagsupport/fntext/begin}{FENote} { \tag_mc_end_push: % \end{macrocode} % test if a footnote is allowed, if not move up to the document structure. % \begin{macrocode} \tag_check_child:nnTF {FENote}{pdf2} { \tag_struct_begin:n { tag=footnote } } { \tag_struct_begin:n { tag=footnote,parent=\l_@@_dflt_struct_tl } } % \end{macrocode} % Store the current structure number for labels. % \begin{macrocode} \tl_set:Ne \l_@@_currentstruct_tl { \tag_get:n{struct_num} } % \end{macrocode} % We want to move the label structure here. So we provide a container % It number is |\l__fnote_currentstruct_tl| plus 1. % \begin{macrocode} \tag_struct_begin:n { tag=footnotelabel }\tag_struct_end: % \end{macrocode} % after we have opened the structure we can use the structure number to % try to detect the connected marks. As with the marks we assume that sometimes % no auto detection is done. % \begin{macrocode} \bool_if:NTF \l_@@_autodetect_bool { % \end{macrocode} % find open marks with identical \cs{@thefnmark} % \begin{macrocode} \fnote_mark_gpop_all:ooN { \@thefnmark }{ \l_fnote_type_tl } \l_@@_currentrefs_seq % \end{macrocode} % Then we store the object numbers of the marks in the /Ref of the FENote structure: % and the number of the FEnote into the marks structure: % \begin{macrocode} \seq_map_inline:Nn \l_@@_currentrefs_seq { \fnote_gput_refs:ee {##1}{ \l_@@_currentstruct_tl } } } % \end{macrocode} % If no auto detection is done % \begin{NOTE}{UF} % TODO: decide what to do here: some label in the optional argument? % or refer to \cs{footref} % \end{NOTE} % \begin{macrocode} {%no auto } } % \end{macrocode} % This finish the setup of the tagging structure. % \end{plugdecl} % Now we process the text. The destinations for the links are set with the label % so that we can be sure that we are in hmode. % \begin{macrocode} \NewSocketPlug{tagsupport/fntext/end}{FENote} { \tag_struct_end: \tag_mc_begin_pop:n{} } % \end{macrocode} % At last assign the plugs: % \begin{macrocode} \AssignSocketPlug{tagsupport/fntext/begin}{FENote} \AssignSocketPlug{tagsupport/fntext/end}{FENote} % \end{macrocode} % % The kernel socket \socket{tagsupport/fntext/mark} is responsible for % tagging the mark in the note. We use it to surround % the mark with the needed tagging commands. % % TODO check if additional kernel configuration points are needed. % If yes, what about the paragraph start and the paratagging?? % % % %^^A If tagging is produced this configuration point is also %^^A responsible for surrounding the mark with the appropriate tags %^^A marking the mark as an Lbl. It does this using the %^^A \socket{tagsupport/fntext/mark} socket. % % \begin{plugdecl}{FENoteLbl} % This plug creates the label in the note on the bottom. % It also adds link targets for the hyperlinking. % \begin{macrocode} \NewSocketPlug{tagsupport/fntext/mark}{FENoteLbl} { \tag_mc_end_push: % \end{macrocode} % We create a link target for every related mark. The name is % \texttt{footnote*} \meta{structure number of the mark}. We also add a link % target for the current structure (for \cs{footref}). % \begin{macrocode} %\seq_show:N\l_@@_currentrefs_seq \seq_map_inline:Nn\l_@@_currentrefs_seq {\MakeLinkTarget*{footnote*.##1}} \MakeLinkTarget*{footnote*.\l_@@_currentstruct_tl} % \end{macrocode} % Now we add the tagging commands. We move the structure of the label to % to the container at the begin of the note. % \begin{NOTE}{UF} % Check if the NonStruct is really needed. Perhaps we can simply move the mc. % \end{NOTE} % \begin{macrocode} \tag_struct_begin:n { tag=NonStruct,parent=\l_@@_currentstruct_tl +1 } \tag_mc_begin:n { tag=Lbl } #1 \tag_mc_end: \tag_struct_end: \tag_mc_begin_pop:n{} } % \end{macrocode} % % \begin{macrocode} \AssignSocketPlug{tagsupport/fntext/mark}{FENoteLbl} % \end{macrocode} % \end{plugdecl} % % %^^A If tagging is produced this configuration point is also %^^A responsible for surrounding the mark with the appropriate tags %^^A marking the mark as an MC of type FENote. It does this using %^^A the socket \socket{tagsupport/fntext/text}. % % \begin{plugdecl}{FENotetext} % % This plug is for the kernel socket \socket{tagsupport/fntext/text} % around the actual note text when doing tagging. % Currently it only adds an MC chunk. % % TODO Should it set a mc or could it rely on the content? % \begin{macrocode} \NewSocketPlug{tagsupport/fntext/text}{FENotetext} { \tag_mc_end_push: \tag_mc_begin:n{} #1 \tag_mc_end: \tag_mc_begin_pop:n{} } % \end{macrocode} % % \begin{macrocode} \AssignSocketPlug{tagsupport/fntext/text}{FENotetext} % \end{macrocode} % \end{plugdecl} %------------------------------------- % \begin{macrocode} \ExplSyntaxOff % % \end{macrocode} % \begin{macrocode} %<@@=> % \end{macrocode} % % \section{Reimplementing the \pkg{footmisc} package} % % \begin{macrocode} %<*footmisc> %% %% Copyright (c) 1995-2011 Robin Fairbairns %% Copyright (c) 2018-2023 Robin Fairbairns, Frank Mittelbach %% %% This file is part of the `latex-lab Bundle'. %% -------------------------------------------- %% %% It 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 %% https://www.latex-project.org/lppl.txt %% and version 1.3c or later is part of all distributions of LaTeX %% version 2008 or later. %% %% This work has the LPPL maintenance status 'maintained'. %% \NeedsTeXFormat{LaTeX2e} \providecommand\DeclareRelease[3]{} \providecommand\DeclareCurrentRelease[2]{} \DeclareRelease{v5}{2011-06-06}{footmisc-2011-06-06.sty} \DeclareCurrentRelease{}{2022-02-14} \ProvidesPackage{latex-lab-footmisc}% [2022/03/08 v6.0d a miscellany of footnote facilities -- latex-lab version% ] \NeedsTeXFormat{LaTeX2e}[2020/10/01] \newtoks\FN@temptoken \providecommand\protected@writeaux{% \protected@write\@auxout } \def\l@advance@macro{\@@dvance@macro\edef} \def\@@dvance@macro#1#2#3{\expandafter\@tempcnta#2\relax \advance\@tempcnta#3\relax #1#2{\the\@tempcnta}% } \let\@advance@macro\l@advance@macro \DeclareOption{symbol}{\renewcommand\thefootnote{\fnsymbol{footnote}}} \newif\ifFN@robust \FN@robustfalse \DeclareOption{symbol*}{% \renewcommand\thefootnote{\@fnsymbol\c@footnote}% \FN@robusttrue \AtEndOfPackage{\setfnsymbol{lamport*-robust}}% } \newif\ifFN@para \FN@parafalse \DeclareOption{para}{% % \end{macrocode} % Options are executed in the order of declaration, thus no point in % checking for side option as footmisc did in the past % \begin{macrocode} % \PackageError{footmisc}{Option "\CurrentOption" incompatible with % option "side"}% % {I shall ignore "\CurrentOption"}% \FN@paratrue \setlength\footnotemargin{-\maxdimen} % default when para is used } % \end{macrocode} % % \begin{macrocode} \DeclareOption{side}{\ifFN@para \PackageError{footmisc}{Option "\CurrentOption" incompatible with option "para"}% {I shall ignore "\CurrentOption"}% \else \AddToHook{fntext/para}{% \hsize\marginparwidth % correct the default \hsize \footnotesep\z@ % don't add a default separation } \AssignSocketPlug{fntext/process}{side} % \AssignSocketPlug{fntext/make}{default} \AssignSocketPlug{fntext/begin}{noop} \AssignSocketPlug{fntext/end}{noop} \fi } \let\footnotelayout\@empty \DeclareOption{ragged}{% \@ifundefined{RaggedRight}% {\renewcommand\footnotelayout{\linepenalty50 \raggedright}}% {\renewcommand\footnotelayout{\linepenalty50 \RaggedRight}}% } \newif\ifFN@perpage \FN@perpagefalse \DeclareOption{perpage}{% \FN@perpagetrue } \newif\ifFN@fixskip \FN@fixskipfalse \let\FN@bottomcases\thr@@ \newif\ifFN@abovefloats \FN@abovefloatstrue \DeclareOption{bottom}{% \let\FN@bottomcases\@ne \FN@abovefloatsfalse \FN@fixskiptrue } \DeclareOption{bottomfloats}{% \let\FN@bottomcases\tw@ \FN@abovefloatstrue \FN@fixskiptrue } \DeclareOption{abovefloats}{\FN@abovefloatstrue \FN@fixskiptrue} \DeclareOption{belowfloats}{\FN@abovefloatsfalse \FN@fixskiptrue} \DeclareOption{marginal}{% \footnotemargin-0.8em\relax } \DeclareOption{flushmargin}{% \footnotemargin0pt\relax } \newif\ifFN@hangfoot \FN@hangfootfalse \DeclareOption{hang}{% \FN@hangfoottrue } \newcommand*\hangfootparskip{0.5\baselineskip} \newcommand*\hangfootparindent{0em}% \DeclareOption{norule}{% \renewcommand\footnoterule{}% \advance\skip\footins 4\p@\@plus2\p@\relax } \DeclareOption{splitrule}{% \gdef\split@prev{0} \let\pagefootnoterule\footnoterule \let\mpfootnoterule\footnoterule \def\splitfootnoterule{\kern-3\p@ \hrule \kern2.6\p@} \def\footnoterule{\relax \ifx \@listdepth\@mplistdepth \mpfootnoterule \else \ifnum\split@prev=\z@ \pagefootnoterule \else \splitfootnoterule \fi \xdef\split@prev{\the\insertpenalties}% \fi }% } \newif\ifFN@stablefootnote \FN@stablefootnotefalse \DeclareOption{stable}{\FN@stablefootnotetrue} \newif\ifFN@multiplefootnote \FN@multiplefootnotefalse \DeclareOption{multiple}{\FN@multiplefootnotetrue} \ProcessOptions % \end{macrocode} % % Footnote box layout for para footnotes; % this would also be the hook to support dblfootnotes (from the % \texttt{dblfnote} package if we integrate that). % \begin{macrocode} \ifFN@para \NewSocketPlug{@makecol/footnotes}{para}{% \global\setbox\footins\vbox{\FN@makefootnoteparagraph}% } \AssignSocketPlug{@makecol/footnotes}{para} \fi % \end{macrocode} % % \begin{macrocode} \ifFN@fixskip \def\@outputbox@removebskip{% \ifx\@textbottom\relax \else \@outputbox@append{% \@tempskipa\lastskip \ifnum \gluestretchorder\@tempskipa>\z@ \vskip-\@tempskipa \xdef\@outputbox@reinsertbskip {\noexpand\@outputbox@append{\vskip\the\@tempskipa}}% \else \global\let\@outputbox@reinsertbskip\relax \fi }% \fi } \let\@outputbox@reinsertbskip\relax \else \let\@outputbox@removebskip \relax \let\@outputbox@reinsertbskip\relax \fi % \end{macrocode} % % % \begin{macrocode} \ifcase \FN@bottomcases\relax \ERROR \or %1 \ifFN@abovefloats \AssignSocketPlug {@makecol/outputbox}{space-footnotes-floats} \else \AssignSocketPlug {@makecol/outputbox}{floats-footnotes-space} \fi \or %2 \ifFN@abovefloats \AssignSocketPlug {@makecol/outputbox}{footnotes-space-floats} \else \AssignSocketPlug {@makecol/outputbox}{space-floats-footnotes} \fi \or %3 \ifFN@abovefloats \AssignSocketPlug {@makecol/outputbox}{footnotes-floats} \else \AssignSocketPlug {@makecol/outputbox}{floats-footnotes} \fi \else \ERROR \fi % next can be dropped when cleaned up \newif\ifFN@setspace \@ifpackageloaded{setspace}% {% \FN@setspacetrue \@ifclassloaded{memoir}% {% \AddToHook{fntext}{\let\baselinestretch\m@m@singlespace}% \let\FN@baselinestretch\m@m@singlespace }% {% % \AddToHook{fntext}{\let\baselinestretch\setspace@singlespace}% \let\FN@baselinestretch\setspace@singlespace }% }% {% \FN@setspacefalse } \ifFN@para % \AssignSocketPlug{fntext/process}{default} \AssignSocketPlug{fntext/make}{para} \AssignSocketPlug{fntext/begin}{noop} \AssignSocketPlug{fntext/end}{para} \fi \ifFN@para \let\FN@tempboxa\@tempboxa \newbox\FN@tempboxb \newbox\FN@tempboxc \newskip\footglue \footglue=1em plus.3em minus.3em %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \newdimen\footnotebaselineskip % establish late: \AddToHook{begindocument/before} {% {% \footnotesize \global\footnotebaselineskip=\normalbaselineskip }% } % \end{macrocode} % The coding is based on David Kastrup's improvement to Don Knuth's % original implementation. You find in the \TeX{}book if you own % the latest edition. % \begin{macrocode} \long\def\FN@makefootnoteparagraph{% \FN@setfootnoteparawidth \@parboxrestore \baselineskip=\footnotebaselineskip \unvbox\footins \FN@removehboxes \RawParEnd } \def\FN@removehboxes{\setbox\FN@tempboxa\lastbox \ifhbox\FN@tempboxa{\FN@removehboxes}% \unhbox\FN@tempboxa \else \RawNoindent \rule\z@\footnotesep \fi } \fi \@ifpackageloaded{multicol} {\def\FN@setfootnoteparawidth {\hsize\ifnum\doublecol@number>\@ne \textwidth \else \columnwidth \fi}} {\def\FN@setfootnoteparawidth{\hsize\columnwidth}} \ifFN@perpage \RequirePackage{perpage} \MakePerPage{footnote} % \end{macrocode} % Fix a bug in perpage \ldots % \begin{macrocode} \def\@stpelt#1{\global\csname c@#1\endcsname \m@ne \stepcounter{#1}% \pp@fix@MakePerPage{#1}% } \def\pp@fix@MakePerPage#1{% \ifnum \value{#1}>\z@ \addtocounter{#1}\m@ne\fi } % \end{macrocode} % The above code may look a bit odd: the \cs{stepcounter} sets the % counter to zero and then we alter it if it is not zero. The % reason is that \cs{stepcounter} resets other counters and when % perpage is loaded this results in updating counters on the reset % list to 1 (or to a higher starting value if \cs{MakePerPage} is % used with an optional argument, which is precisely the problem % here). By subtracting 1 in that case we set it back to 1 lower % than the starting value. % % But to make this fully work we also need to update a support % command in \pkg{perpage}: % \begin{macrocode} \def\pp@cl@end@iii\stepcounter#1\pp@fix@MakePerPage#2{} \fi \ifFN@para % This can use the default interface, except that a negative value for % \footnotemargin makes little sense, so we test for this and warn if % necessary. But -\maxdimen is ok again, so would need to be a litte bit more elaborate. % %\AddToHook{fntext/para}{ % \ifdim \footnotemargin >\z@ \else % \PackageWarningNoline{footmisc}{Option 'para' needs positive \noexpand\footnotemargin}% % \footnotemargin 1.8em\relax % \fi %} \AddToHook{fntext/begin}{\nobreak \hspace{.2em}} \else \ifFN@hangfoot \long\def\@makefntext#1{% \bgroup \setbox\@tempboxa\hbox{% \ifdim\footnotemargin>\z@ \hb@xt@\footnotemargin{\@makefnmark\hss}% \else \@makefnmark \fi }% \leftmargin\wd\@tempboxa \rightmargin\z@ \linewidth \columnwidth \advance \linewidth -\leftmargin \parshape \@ne \leftmargin \linewidth \footnotesize \@setpar{{\@@par}}% \leavevmode \llap{\box\@tempboxa}% \parskip\hangfootparskip\relax \parindent\hangfootparindent\relax \footnotelayout#1% \par \egroup } \else % This is now using the default interface: % % \long\def\@makefntext#1{% % \parindent1em % \noindent % \ifdim\footnotemargin>\z@ % \hb@xt@ \footnotemargin{\hss\@makefnmark}% % \else % \ifdim\footnotemargin=\z@ % \llap{\@makefnmark}% % \else % \llap{\hb@xt@ -\footnotemargin{\@makefnmark\hss}}% % \fi % \fi % \footnotelayout#1% % } \fi \fi \ifFN@multiplefootnote \providecommand*{\multiplefootnotemarker}{3sp} % \end{macrocode} % % We tag the separator as artifact % \fmi{why is this done with \cs{providecommand}?} % \begin{macrocode} \ExplSyntaxOn \providecommand*{\multfootsep}{\tag_mc_end_push:\tag_mc_begin:n{artifact},\tag_mc_end:\tag_mc_begin_pop:n{}} \ExplSyntaxOff \AddToHook{fnmark} {\FN@mf@check} \AddToHook{fnmark/end} {\FN@mf@prepare} % \def\FN@mf@prepare{% \kern-\multiplefootnotemarker \kern\multiplefootnotemarker\relax } \def\FN@mf@check{% \ifdim\lastkern=\multiplefootnotemarker\relax %?? is that necessary or even correct ?? \edef\@x@sf{\the\spacefactor}% %?? shouldn't that be 2 unkerns ?? (none would also be ok) \unkern % new \unkern \textsuperscript{\multfootsep}% \spacefactor\@x@sf\relax \fi } \else \let\FN@mf@prepare\relax \fi \ifFN@stablefootnote \let\FN@sf@@footnote\footnote \def\footnote{\ifx\protect\@typeset@protect \expandafter\FN@sf@@footnote \else \expandafter\FN@sf@gobble@opt \fi } \edef\FN@sf@gobble@opt{\noexpand\protect \expandafter\noexpand\csname FN@sf@gobble@opt \endcsname} \expandafter\def\csname FN@sf@gobble@opt \endcsname{% \@ifnextchar[%] \FN@sf@gobble@twobracket \@gobble } \def\FN@sf@gobble@twobracket[#1]#2{} \let\FN@sf@@footnotemark\footnotemark \def\footnotemark{\ifx\protect\@typeset@protect \expandafter\FN@sf@@footnotemark \else \expandafter\FN@sf@gobble@optonly \fi } \edef\FN@sf@gobble@optonly{\noexpand\protect \expandafter\noexpand\csname FN@sf@gobble@optonly \endcsname} \expandafter\def\csname FN@sf@gobble@optonly \endcsname{% \@ifnextchar[%] \FN@sf@gobble@bracket {}% } \def\FN@sf@gobble@bracket[#1]{} \fi \newcommand\setfnsymbol[1]{% \@bsphack \@ifundefined{FN@fnsymbol@#1}% {% \PackageError{footmisc}{Symbol style "#1" not known}% \@eha }{% \expandafter\let\expandafter\@fnsymbol\csname FN@fnsymbol@#1\endcsname }% \@esphack } \let\FN@fnsymbol@lamport\@fnsymbol \newif\if@tempswb \DeclareDocumentCommand\DefineFNsymbols {smO{text}m}{% \expandafter\ifx\csname FN@fnsymbol@#2\endcsname\relax \PackageInfo{footmisc}{Declaring symbol style #2}% \else \PackageWarning{footmisc}{Redeclaring symbol style #2}% \fi \toks@{}% \def\@tempb{\end}% \FN@build@symboldef#4\end \def\@tempc{math}% \def\@tempd{#3}% \expandafter\xdef\csname FN@fnsymbol@#2\endcsname##1{% \ifx\@tempc\@tempd \noexpand\ensuremath \else \noexpand\nfss@text \fi {% \noexpand\ifcase##1% \the\toks@ \noexpand\else \IfBooleanTF#1{\noexpand\@ctrerr}% {\noexpand\FN@orange##1}% \noexpand\fi }% }% } \def\FN@build@symboldef#1{% \def\@tempa{#1}% \ifx\@tempa\@tempb \else \toks@\expandafter{\the\toks@\or#1}% \expandafter\FN@build@symboldef \fi } \DeclareDocumentCommand\DefineFNsymbolsTM {smm}{% \expandafter\ifx\csname FN@fnsymbol@#2\endcsname\relax \PackageInfo{footmisc}{Declaring symbol style #2}% \else \PackageWarning{footmisc}{Redeclaring symbol style #2}% \fi \toks@{}% \def\@tempb{\end}% \FN@build@symboldefTM#3\end\@null \expandafter\xdef\csname FN@fnsymbol@#2\endcsname##1{% \noexpand\ifcase##1% \the\toks@ \noexpand\else \IfBooleanTF#1{\noexpand\@ctrerr}% {\noexpand\FN@orange##1}% \noexpand\fi }% } \def\FN@build@symboldefTM#1#2{% \def\@tempa{#1}% \ifx\@tempa\@tempb \else \toks@\expandafter{\the\toks@\or\TextOrMath{#1}{#2}}% \expandafter\FN@build@symboldefTM \fi } \def\FN@orange#1{% \ifFN@robust \@arabic#1% \@bsphack \PackageInfo{footmisc}{Footnote number \number#1 out of range}% \protect\@fnsymbol@orange \@esphack \else \@ctrerr \fi } \global\let\@diagnose@fnsymbol@orange\relax \AtEndDocument{\@diagnose@fnsymbol@orange} \def\@fnsymbol@orange{% \gdef\@diagnose@fnsymbol@orange{% \PackageWarningNoLine{footmisc}{Some footnote number(s) were out of range \MessageBreak see log for details% }% }% } \DefineFNsymbolsTM{bringhurst}{% \textasteriskcentered *% \textdagger \dagger \textdaggerdbl \ddagger \textsection \mathsection \textbardbl \|% \textparagraph \mathparagraph }% \DefineFNsymbolsTM{chicago}{% \textasteriskcentered *% \textdagger \dagger \textdaggerdbl \ddagger \textsection \mathsection \textbardbl \|% \#\#% }% \DefineFNsymbolsTM{wiley}{% \textasteriskcentered *% {\textasteriskcentered\textasteriskcentered}{**}% \textdagger \dagger \textdaggerdbl \ddagger \textsection \mathsection \textparagraph \mathparagraph \textbardbl \|% }% \DefineFNsymbolsTM{lamport-robust}{% \textasteriskcentered *% \textdagger \dagger \textdaggerdbl \ddagger \textsection \mathsection \textparagraph \mathparagraph \textbardbl \|% {\textasteriskcentered\textasteriskcentered}{**}% {\textdagger\textdagger}{\dagger\dagger}% {\textdaggerdbl\textdaggerdbl}{\ddagger\ddagger}% } \DefineFNsymbolsTM*{lamport*}{% \textasteriskcentered *% \textdagger \dagger \textdaggerdbl \ddagger \textsection \mathsection \textparagraph \mathparagraph \textbardbl \|% {\textasteriskcentered\textasteriskcentered}{**}% {\textdagger\textdagger}{\dagger\dagger}% {\textdaggerdbl\textdaggerdbl}{\ddagger\ddagger}% {\textsection\textsection}{\mathsection\mathsection}% {\textparagraph\textparagraph}{\mathparagraph\mathparagraph}% {\textasteriskcentered\textasteriskcentered\textasteriskcentered}{***}% {\textdagger\textdagger\textdagger}{\dagger\dagger\dagger}% {\textdaggerdbl\textdaggerdbl\textdaggerdbl}{\ddagger\ddagger\ddagger}% {\textsection\textsection\textsection}%% {\mathsection\mathsection\mathsection}% {\textparagraph\textparagraph\textparagraph}%% {\mathparagraph\mathparagraph\mathparagraph}% } \setfnsymbol{lamport*} \DefineFNsymbolsTM{lamport*-robust}{% \textasteriskcentered *% \textdagger \dagger \textdaggerdbl \ddagger \textsection \mathsection \textparagraph \mathparagraph \textbardbl \|% {\textasteriskcentered\textasteriskcentered}{**}% {\textdagger\textdagger}{\dagger\dagger}% {\textdaggerdbl\textdaggerdbl}{\ddagger\ddagger}% {\textsection\textsection}{\mathsection\mathsection}% {\textparagraph\textparagraph}{\mathparagraph\mathparagraph}% {\textasteriskcentered\textasteriskcentered\textasteriskcentered}{***}% {\textdagger\textdagger\textdagger}{\dagger\dagger\dagger}% {\textdaggerdbl\textdaggerdbl\textdaggerdbl}{\ddagger\ddagger\ddagger}% {\textsection\textsection\textsection}%% {\mathsection\mathsection\mathsection}% {\textparagraph\textparagraph\textparagraph}%% {\mathparagraph\mathparagraph\mathparagraph}% } \newcommand\mpfootnotemark{% \@ifnextchar[%] \@xmpfootnotemark {% \stepcounter\@mpfn \protected@xdef\@thefnmark{\thempfn}% \@footnotemark }% } \def\@xmpfootnotemark[#1]{% \begingroup \csname c@\@mpfn\endcsname #1\relax \unrestored@protected@xdef\@thefnmark{\thempfn}% \endgroup \@footnotemark } % \end{macrocode} % TEMP PATCHES FOR TESTING % \begin{macrocode} \endinput % % \end{macrocode} % \Finale %