[Tex/LaTex] Why does \parbox lose footnotes

boxesfootnotes

The motivation is presumably that footnotes are formatted immediately and inside a parbox \hsize does not equal \textwidth (although, unlike a minipage, \textwidth doesn't change). The mechanism is presumably simply using local rather than global definitions. Looking through source2e I couldn't find the source for \@makefntext. I was hoping to be able to fix the problem directly.

Anyway, here is a sort of MWE:

\documentclass{article}

\newcount\savefnused
\newcount\savefndone

\newcommand{\savefootnote}[2][\empty]% #1=number (optional), #2=text
{\ifx\empty#1\footnotemark\else\footnotemark[#1]\fi
 \global\advance\savefnused by 1
 \expandafter\xdef\csname savefnmark\the\savefnused\endcsname{\thefootnote}%
 \expandafter\xdef\csname savefntext\the\savefnused\endcsname{#2}%
}
\newcommand{\flushfootnote}{\loop\ifnum\savefndone<\savefnused
  \global\advance\savefndone by 1
  \footnotetext[\csname savefnmark\the\savefndone\endcsname]%
    {\csname savefntext\the\savefndone\endcsname}%
  \global\expandafter\let\csname savefnmark\the\savefndone\endcsname\relax
  \global\expandafter\let\csname savefntext\the\savefndone\endcsname\relax
\repeat}

\begin{document}
normal\footnote{normal}

\parbox{1in}{parbox\savefootnote{parbox}}
\flushfootnote

check counter\footnote{after}

\end{document}

Best Answer

My understanding now is that \insert\footins{...} will cause anything written inside the group to wind up in \box\footins but only AFTER the page is output. Also, \global\insert is not allowed.

The macro \global@insert doesn't precisely mimic the \insert "migration" in that the contents show up immediately, but it seems to work good enough for footnotes.

\documentclass{article}
\usepackage{blindtext}

\makeatletter
\newcommand{\global@insert}[2]% #1=box number, #2=vertical list
{\bgroup
  \setbox\@tempboxa=\box#1
  \global\setbox#1=\vbox{\unvbox\@tempboxa #2}
\egroup}

\long\def\@footnotetext#1{\global@insert\footins{%
 \reset@font\footnotesize
 \interlinepenalty\interfootnotelinepenalty
 \splittopskip\footnotesep
 \splitmaxdepth \dp\strutbox \floatingpenalty \@MM
 \hsize\columnwidth \@parboxrestore
 \protected@edef\@currentlabel{%
 \csname p@footnote\endcsname\@thefnmark
 }%
 \color@begingroup
 \@makefntext{%
 \rule\z@\footnotesep\ignorespaces#1\@finalstrut\strutbox}%
 \color@endgroup}}%
\makeatother

\begin{document}
normal\footnote{normal}

\begin{enumerate}
\item\parbox{1in}{parbox\footnote{parbox - \blindtext}}
\item test
\end{enumerate}

check counter\footnote{after}

\end{document}

This approach uses normal footnotes outside the \parbox, but requires a bit more work. Basically it works like \footnotemark and \footnotetext except that you don't have to keep track of which mark goes with which text.

Inside the \parbox you need to add \globalfootnotestrue to switch modes. After the parbox you need to add \copyinserts to move the footnotes from \parboxins to \footins. Since \parbox is unbreakable, you don't have to worry about winding up on the wrong page.

\documentclass{article}
\usepackage{blindtext}

\makeatletter
\newsavebox{\parboxins}
\newif\ifglobalfootnotes

\newcommand{\copyinserts}{\insert\footins{\unvbox\parboxins}%
  \globalfootnotesfalse}% should be redundant

\newcommand{\global@insert}[2]% #1=box number, #2=vertical list
{\bgroup
  \setbox\@tempboxa=\box#1
  \global\setbox#1=\vbox{\unvbox\@tempboxa #2}
\egroup}

\long\def\@footnotetext#1{%
 \protected@edef\@currentlabel{\csname p@footnote\endcsname\@thefnmark}%
 \ifglobalfootnotes \global@insert\parboxins{\@@footnotetext{#1}}%
 \else \insert\footins{\@@footnotetext{#1}}%
 \fi}

\long\def\@@footnotetext#1{%
 \color@begingroup
 \reset@font\footnotesize
 \interlinepenalty\interfootnotelinepenalty
 \splittopskip\footnotesep
 \splitmaxdepth \dp\strutbox \floatingpenalty \@MM
 \hsize\columnwidth \@parboxrestore
 \@makefntext{\rule\z@\footnotesep\ignorespaces#1\@finalstrut\strutbox}%
 \color@endgroup}
\makeatother

\begin{document}
normal\footnote{normal}

\begin{enumerate}
\item \parbox[t]{\linewidth}{\globalfootnotestrue
  parbox\footnote{parbox - \blindtext}}%
\copyinserts
\item test
\end{enumerate}

check counter\footnote{after}

\end{document}
Related Question