I came across the issue hinted at in the title while I was reflecting on this question (“Irregular spacing around a user-defined environment”) and its answer.
The \@endparenv
command is called by all “list-making”
environments (via \endtrivlist
) to ensure that “LaTeX begins a
new paragraph if and only if you leave a blank line after the
\end
command” (quoted from ltlists.dtx
). It does so by
applying a “temporary change” (in the sense specified by
ltpar.dtx
) to the meaning of \par
at the very end of the
environment itself. On the other hand, “list-making”
environments also need to apply a “long-term change” to \par
during their initialization phase, more precisely when
\@trivlist
is executed (see ltlists.dtx
2015/05/10, lines
78–86). The mechanism devised in ltpar.dtx
for changing the
meaning of \par
ensures that these two changes work together in
a consistent way when “list-making” environments are nested
within one another.
However, I was wondering whether this mechanism behaves
correctly, in the current LaTeX kernel, also when a list
environment appears inside a minipage
that is itself nested
within another list environment: indeed, it seems reasonable
that, in this case, the minipage
should act as a “sandbox”,
“shielding”, so to speak, the inner environment from the outer
one; but this is not what currently happens, as the following
example shows. Actually, the example doesn’t directly use a list
environment, but flushleft
, which, however, is implemented by
means of \trivlist
; this is done to remain closer to the
situation discussed in
the aforementioned question.
You are invited to compile the following code and to examine its output, as well as the source code itself, before reading on.
% My standard header for TeX.SX answers:
\documentclass[a4paper]{article} % To avoid confusion, let us explicitly
% declare the paper format.
\usepackage[T1]{fontenc} % Not always necessary, but recommended.
\usepackage[ascii]{inputenc} % Just to check that the source is still pure,
% 7-bit-clean ASCII when you execute it, as it
% was when I wrote it.
% End of standard header. What follows pertains to the problem at hand.
\makeatletter
\newcommand*\@SHOW[1]{%
\texttt{\char\escapechar #1} $\Longrightarrow$
\texttt{\expandafter\meaning\csname #1\endcsname}%
}
\newcommand*\SHOW{%
\myNL\@SHOW{par}\myNL\@SHOW{@par}%
}
\newcommand*\MyParShape{%
\hangafter \@ne \hangindent \thr@@ pc \noindent
}
\newcommand*\myNL{\hfill\break}
\makeatother
\begin{document}
\section{Base scenario}
\label{S:Base}
Consider the following:
\begin{flushleft}
Some text marked~(A)\@.
\end{flushleft}
Not preceded by blank line:\SHOW
\begin{flushleft}
Some text marked~(B)\@.
\end{flushleft}
Preceded by blank line:\SHOW
\MyParShape
All this is quite OK\@. This paragraph does have hanging indentation,
but the following one won't\ldots
\ldots as you can see here. Lorem ipsum dolor sit amet consectetur adipisci
elit, ridiculus mus. Fringilla eius partorietur.
\section{\texttt{flushleft} inside \texttt{flushleft}}
\label{S:fl<fl}
Now consider:
\begin{flushleft}
\setlength{\parindent}{1pc}
We nest here the same contruction presented in Section~\ref{S:Base}:
\begin{flushleft}
Some text marked~(C)\@.
\end{flushleft}
Not preceded by blank line:\SHOW
\begin{flushleft}
Some text marked~(D)\@.
\end{flushleft}
Preceded by blank line:\SHOW
\MyParShape
This paragraph has hanging indentation, but this time the hanging
indentation is carried over also to the following one.
But this could be considered OK\@ too, because, after all, we are still
inside the \texttt{list} environment implied by the outer
\texttt{flushleft}: indeed, preserving \verb|\parshape| setting is essential
for the implementation of ``list-making'' environments. And
\texttt{flushleft} environments should \textbf{not} be nested!
\end{flushleft}
Not preceded by blank line:\SHOW
Again, this is what we expect.
\section{\texttt{flushleft} inside \texttt{minipage} inside \texttt{flushleft}}
\label{S:fl<mp<fl}
But consider this other situation:
\begin{flushleft}
\begin{minipage}[b]{.9\linewidth}
\raggedright % to avoid underfull boxes
\setlength{\parindent}{1pc}
Start of the \texttt{minipage}. Note that \verb|\par| has its primitive
meaning:\SHOW
Also here, we nest the same contruction presented in
Section~\ref{S:Base}:
\begin{flushleft}
Some text marked~(E)\@.
\end{flushleft}
Not preceded by blank line:\SHOW
\begin{flushleft}
Some text marked~(F)\@.
\end{flushleft}
Preceded by blank line:\SHOW
\MyParShape
As we see, the meaning of \verb|\par| has not reverted to what it was at
the beginning. Why is this not good at all? Well, for a number of
reasons, of which the fact that hanging indentation is carried over from
one paragraph to another,\ldots
(\emph{continuing from the previous paragraph}) \ldots as you can see
here, is just the first---and rather silly---example that comes to my
mind. Lorem ipsum dolor sit amet consectetur adipisci elit, ridiculus
mus. Fringilla eius partorietur.
End of the \texttt{minipage}.
\end{minipage}
Thus, we see that, inside the \texttt{minipage}, we do \emph{not} get the
same behavior as in the ``base scenario'' of Section~\ref{S:Base}, but
rather the behavior of Section~\ref{S:fl<fl}.
\end{flushleft}
Should this be considered a (tiny) bug in the \LaTeXe\ kernel?
\clearpage
\makeatletter
\def\@minipagerestore{%
\def\@par{\let\par\@@par\par}
}
\makeatother
\section{Possible fix}
\label{S:Fix}
Consider, finally, what happens now:
\begin{flushleft}
\begin{minipage}[b]{.9\linewidth}
\raggedright % to avoid underfull boxes
\setlength{\parindent}{1pc}
Start of the \texttt{minipage}. Note that \verb|\par| has its primitive
meaning:\SHOW
Once more, we nest here the same contruction presented in
Section~\ref{S:Base}:
\begin{flushleft}
Some text marked~(G)\@.
\end{flushleft}
Not preceded by blank line:\SHOW
\begin{flushleft}
Some text marked~(H)\@.
\end{flushleft}
Preceded by blank line:\SHOW
\MyParShape
As we see, this time the meaning of \verb|\par| \emph{has} reverted to
what it was at the beginning. Indeed, hanging indentation is no longer
being carried over from one paragraph to another,\ldots
(\emph{continuing from the previous paragraph}) \ldots as you can see
here. Lorem ipsum dolor sit amet consectetur adipisci elit, ridiculus
mus. Fringilla eius partorietur.
End of the \texttt{minipage}.
\end{minipage}
Thus, we see that, inside the \texttt{minipage}, we \emph{do} get, now, the
same behavior as in the ``base scenario'' of Section~\ref{S:Base}.
\end{flushleft}
\end{document}
Note that we manually reset \parindent
in some places to make
the effects of \@endparenv
visible. The document you obtain
contains four sections.
In the first section, a simple, top-level use of a
flushleft
environment is exemplified, to serve as a benchmark
for the other cases that are presented below. Here we see how
the “temporary change” that \@endarenv
makes to the meaning of
\par
is undone when it occurs by itself, without a concurrent
“long-term change” being pending.
The second section illustrates the case of direct nesting.
The result may look strange at first, but this happens only
because one does not immediately realize that the inner
flushleft
is actually a second-level list nested within the
first-level list represented by the outer flushleft
. Actually,
the typical users will be unaware of this, because they will not
know the details of how flushleft
is implemented, and the best
advice that could be given to them is to avoid nesting
center
/flushleft
/flushright
environments.
In the third section, however, the situation is dimmer:
shouldn’t the flushleft
environment included in the minipage
behave in the same way as the top-level one shown in the first
section, irrespective of the fact that the minipage
itself is,
in turn, included in another flushleft
(or center
, or
flushright
environment? Or even in a list? Actually,
minipage
resets \par
to its original meaning, but—aha!—it fails
to similarly reset \@par
, so that the “long-term change” made
by the outer list percolates, as it were, down to the inner one,
thus determining the same result as in the case of direct
nesting.
Finally, the fourth section presents a possible, and even too
obvious fix: include the resetting of \@par
at the beginning of
minipage
s. Here this is done by means of the
\@minipagerestore
hook.
My question is: is the foregoing analysis correct or not? And,
connected to this: are there other aspects I have not considered,
which imply that the choice of not having the minipage
environment redefine \@par
is intentional?