Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

Quoting from the LaTeX2e sources:

[\@endparenv, \@doendpe]

To suppress the paragraph indentation in text immediately following a paragraph-making environment, \everypar is changed to remove the space, and \par is redefined to restore \everypar. Instead of redefining \par and \everpar, \@endparenv was changed to set the @endpe switch, letting \end redefine \par and \everypar.

This allows paragraph-making environments to work right when called by other environments. (Changed 27 Oct 86)

These are the relevant code lines (with line breaks added to improve readability):

\def\@endparenv{%
  \addpenalty\@endparpenalty
  \addvspace\@topsepadd
  \@endpetrue
}
\def\@doendpe{%
  \@endpetrue% <---?
  \def\par{%
    \@restorepar
    \everypar{}%
    \par
    \@endpefalse% <---?
  }%
  \everypar{%
    {\setbox\z@\lastbox}%
    \everypar{}%
    \@endpefalse% <---?
  }%
}

While I roughly comprehend \@doendpe and its \everypar trickery, I'm lost with regard to two details (marked with <---? in the above code):

  • As the definition of \begin includes \@endpefalse, why is it necessary to set \@endpefalse at the end of \@doendpe's \par/\everypar redefinitions?

  • Why is setting \@endpetrue at the start of \@doendpe necessary? Isn't \@doendpe only called if the @endpe switch is set to true?

I suspect that a possible answer involves the (to me) cryptical remark about "paragraph-making environments [working] right when called by other environments", but would be grateful for a full explanation.

Bonus question: If I were to define a custom list environment that at its end would set \@endpefalse and instead (with the appropriate \aftergroup) call a carbon copy of \@doendpe (say \@doendcustomenv), would the code lines marked wih <---? above be beneficial or superfluous in this copy?

share|improve this question
    
Good question. I was asking me the same when I wrote on macros2e. –  Martin Scharrer Jul 30 '11 at 17:42
1  
@Martin: I didn't assume my question was that good. ;-) –  lockstep Jul 30 '11 at 17:43
1  
I suspect that this has something to do with lrbox that does some trickery with grouping. It does \@endpefalse at some point. –  egreg Jul 30 '11 at 22:28
add comment

1 Answer

up vote 17 down vote accepted

For our purposes, \begin{#1} is roughly

\begingroup \@endpefalse \csname #1\endcsname

and \end{#1} is roughly

\csname end#1\endcsname\expandafter \endgroup \if@endpe \@doendpe \fi

Since \expandafter expands \if@endpe before the group ends, the value of the switch that is used is the one within the environment. If the \csname #1\endcsname part of a \begin{#1} features \@endpetrue, then \@doendpe will be expanded. However, it will be expanded outside the environment, where the switch has been returned to its former value.

Consider the following document. The environment parenvA suppresses the indentation afterwards. In the second case, \@endparenv is called within two groups, and causes \@doendpe to be called still within the parenvB environment. If the definition of \@doendpe did not have \@endpetrue, then it would simply define \par and \everypar within the parenvB environment. These definitions would disappear at the end of the group, and the next paragraph would be indented. So instead, \@doendpe makes sure to carry the truth of the switch with it beyond environment boundaries, until the next \par or \everypar.

\documentclass{article}
\makeatletter
\newenvironment{parenvA}{}{\par\@endparenv}
\newenvironment{parenvB}{}{}
\makeatother
\usepackage{lipsum}
\begin{document}
% case 1
\begin{parenvA}
  \lipsum[1]
\end{parenvA}
\lipsum[2]
% case 2
\begin{parenvB}
  \begin{parenvA}
    \lipsum[3]
  \end{parenvA}
\end{parenvB}
\lipsum[4]
% case 3
\begin{parenvB}
  \begin{parenvA}
    \lipsum[5]
  \end{parenvA}
  \lipsum[6]
\end{parenvB}
\lipsum[7]
\end{document}

Once this is established, both \par and \everypar must have \@endpefalse, otherwise the last paragraph in the example above would lose its indentation: indeed, the \@doendpe triggered just outside the parenvA environment contains \@endpetrue, but we don't want the indentation to be suppressed after that \end{parenvB}, because there has already been a paragraph.

Now why do we need to work with both \everypar and \par? Because there are actually two cases. If the user leaves no blank line after \end{parenvA}, then the first letter, inherently horizontal for TeX, causes \everypar to be inserted, and to eat the indentation (with \lastbox). However, if the user leaves a blank line, TeX's eyes replace that by a \par token, which resets the normal definitions of \par and \everypar, and do not eat any indentation (try adding some blank lines in the file above and see what happens).

For your bonus question, well, if you remove those lines, the indentation will only be removed if the next \par (blank line) or \everypar (triggered by horizontal material) is within the same group/environment. Not necessarily what you want.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.