28

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 minipages. 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?

3
  • 1
    Nice question :-).
    – cfr
    Commented May 1, 2016 at 16:20
  • I believe that Frank should answer
    – egreg
    Commented May 2, 2016 at 7:55
  • @egreg Can you ping Frank? :-)
    – Johannes_B
    Commented May 8, 2016 at 6:19

1 Answer 1

1

Some Five years later!

There are fifty shades of \par in LaTeX! The OP did a number of tests in my opinion in a very complicated way and concluded that there might be a bug in LaTeX. Fortunately there is no bug!

The OP based his conclusions that after he inserted a special macro \MyParshape, based on \hangafter\hangindent, and this carried over in more paragraphs, this was a possible bug. Had he inserted a \@@par in the paragraaph before his macro at the time everything would have been ok. Now I had to save \@@par in the preamble and use it in the test (since we have the new hook systems now and there are other complications now). In lists this behavior is correct, as there might be more levels of lists and the program needs to keep the \par under control. The OP should have made sure that \MyParShape in a list worked correctly, by defining it appropriately.

I attach the image of my tests and the code. I removed OP's code that was unecessary. We only need to test for three conditions a) value of par in normal paragraphs, its value in minipages and its value in lists. TEST 9, resolved the OP's question.

By the way the \par now has a twin sister, and when we say \par we get two! un-comment the end of the code below to get a surprise!

\documentclass[a4paper]{scrartcl} 
\usepackage{xcolor}
\definecolor{green}{rgb}{0.06,0.44,0.08}
\makeatletter
\newcommand*\MyParShape{%
    \hangafter \@ne \hangindent \thr@@ pc \noindent
}
\ExplSyntaxOn
\let\ATATPAR\@@par
\def\LISTPAR{\if@newlist \advance \par@deathcycles \@ne \ifnum \par@deathcycles >\@m 
\@noitemerr {\@@par }\fi \else {\@@par }\fi} 
\def\PASS{{\ttfamily\color{green} ~ PASS~}}
\def\FAIL{{\ttfamily\color{red} ~ FAIL~}}
\int_new:N \testcounter
\int_gset:Nn \testcounter{1}
\cs_gset:Npn\TEST #1#2#3
{ \makeatletter
  \int_use:N \testcounter :~~
  \token_if_eq_meaning:NNTF #1#2{\PASS}{\FAIL}
  {\ttfamily \tl_to_str:n {#3} }
  \int_gincr:N \testcounter
}
\ExplSyntaxOff
\makeatother
\parindent0pt
\begin{document}

\makeatletter

\subsection*{At start of document}
\TEST{\par}{\@@par}{\par==\@@par}\par
\ExplSyntaxOn
\TEST{\par}{\tex_par:D}{\par != \tex_par:D }

\ExplSyntaxOff

\subsection*{In minipage tests}

\begin{minipage}{1\linewidth}
\TEST{\par}{\ATATPAR}{In minipage \par == \@@par}\par
\end{minipage}

\subsection*{In flushleft tests}
\begin{flushleft}
    \TEST{\par}{\@par}{in flush left \par=\@par (in list definition)}\par
    Some text marked~(A).
\end{flushleft}
\subsection*{Between flush left environments}
\TEST{\par}{\@@par}{between two flush enviroments \par=\@@par l3 wins}  % TEST 5
\makeatother
\begin{flushleft}
    Some text marked~(B).
\end{flushleft}

\subsection*{Nested minipage in flushleft}
\begin{flushleft}
\raggedright
    \begin{minipage}[b]{.9\linewidth}
    \makeatletter
       \TEST{\par}{\@@par}{In a list first line of minipage \par=\@@par}\par
   
       \begin{flushleft}
            \TEST{\par}{\@par}{In flusleft>minipage>flushleft \par=\@par (list def.)}
            Some text marked~(E).
        \end{flushleft}
        Not preceded by blank line:\par
        \makeatletter 
        \TEST{\@par}{\LISTPAR}{In list \par=\@par i.e, as defined in lists}
        \makeatother
        \begin{flushleft}
            Some text marked~(F).
        \end{flushleft}
        \MyParShape
        \color{orange}
        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\color{black}\ATATPAR
       
        \makeatletter
        \TEST{\@par}{\LISTPAR}{After \MyParshape \par=\@par=\LISTPAR}
        \makeatother
        
        Continuing from the previous paragraph \ldots as you can see
        here\ldots. There is no issue with the \verb+\MyParShape+!
    \end{minipage}
    
\end{flushleft}


%\ttfamily
%\ExplSyntaxOn
%\meaning\par
%
%
%\meaning\tex_par:D\par
\end{document}

enter image description here

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .