8

I'd like to execute something at every end of a paragraph (writing sth. to aux file). So I modified \par using

\let\oldpar\par
\def\par{%
    \protected@write\@auxout{}{\string\ParHere}%
    \oldpar% original version of \par
}%

That works pretty well, until a trivlist-based environment (enumerate, itemize, center, quote etc.) is used, which seems to be magically resetting \par to just the original \par.

MWE:

\documentclass{article}
\usepackage{etoolbox}
\makeatletter
\def\ParHere{}
\let\oldpar\par
\def\par{%
    \protected@write\@auxout{}{\string\ParHere}%
    \oldpar% original version of \par
}
%Attempt for solution which doesn't work:  
%\appto\endtrivlist{%
%   \gdef\par{%
%       \protected@write\@auxout{}{\string\ParHere}%
%       \oldpar%
%   }%
%}
\makeatother
\begin{document}
Hallo % Makes \ParHere appearing in aux-file.
\begin{center}
    Centered Text.
\end{center}
More paragraphs 

But not more ParHere entries created in the auxfile. 

asd
\end{document}

So it seems \par is somehow reset in a trivlist environment – fine. But what really gives me headache is: Even if I add

\appto\endtrivlist{%
    \gdef\par{%
        \protected@write\@auxout{}{\string\ParHere}%
        \oldpar%
    }%
}

to the preamble, the \par command will not be back to normal after the center (or any other trivlist-based) environment. But if I manually introduce a

\makeatletter
\def\par{%
    \protected@write\@auxout{}{\string\ParHere}%
    \oldpar%
}
\makeatother

after \end{center}, everything works.

So, why can I not reset \par to my custom definition by using \appto\endtrivlist? Does anyone have a solution?

PS: I guess it is generally not elegant to redefine \par globally? If so, what else could I do? Please note that redefining \everypar does not work to me as I really need to execute the aux-file-write at end of a paragraph.

  • the \par primitive is saved in the macro \@@par you can use it. – touhami Mar 15 '17 at 21:35
  • Thanks! I edited the question, removing my \let\oldpar\par and instead using \@@par. – LaTechneuse Mar 15 '17 at 21:42
  • 1
    \par is redefined in multiple places all over latex, you can only do this in very restricted contexts. headings, lists, parboxes, floats .... all reset \par – David Carlisle Mar 15 '17 at 22:53
  • 2
    is lualatex a possibility? a lua callback eg post_linebreak_filter gets called whenever tex breaks a paragraph into lines so you can write whatever you want to write from Lua at that point. – David Carlisle Mar 15 '17 at 23:20
  • 1
    I don't see how anybody can say what else you could do without knowing what you are trying to do. – cfr Mar 16 '17 at 2:25
8

Your first question, “Why can I not reset \par to my custom definition by using \appto\endtrivlist?”, is pretty easy to answer, but your second one, where you ask for advice on what to do instead, requires that you specify in greater detail what you want to achieve—and please note that this is only a necessary, but not sufficient condition. (:-)

Let’s look in detail at what happens when you execute, say,

\end{center}

The first thing that the TeX compiler actually does is to expand the \end macro, which is defined in the LaTeX kernel as follows:

\def\end#1{%
  \csname end#1\endcsname\@checkend{#1}%
  \expandafter\endgroup\if@endpe\@doendpe\fi
  \if@ignore\@ignorefalse\ignorespaces\fi}

(see the file latex.ltx, lines 4157–4160; but note that the version of this file which is installed on the computer I’m currently writing on is 2017/01/01, patch level 1: I’m not sure that it is the latest release). So, the next step is to execute

\csname endcenter\endcsname

that is, \endcenter; this is defined on line 4171:

\def\endcenter{\endtrivlist}

OK, at this point \endtrivlist is executed, and let us suppose that it contains your custom addition that resets the meaning of \par. But there is still more code awaiting to be executed as part of the expansion of \end{center}. The next piece is

\@checkend{center}

which is the macro that checks that \begin and \end declarations are correctly paired, and which plays no rôle in our present discussion. Then comes

\expandafter\endgroup\if@endpe\@doendpe\fi

This construct expands the \if@endpe conditional before ending the current group (which is the group that was started by \begin{center}): what’s this? Well, if you look at the definition of \endtrivlist (which, in my version of latex.ltx, begins on line 4616), you’ll see that one of the last things that gets executed is the \@endparenv macro (the @noparlist switch is certainly false in our context—provided that your center environment is not empty—I must ask you to trust me about this, because I cannot explain all the details); this macro is defined immediately below, at lines 4638–4639:

\def\@endparenv{%
  \addpenalty\@endparpenalty\addvspace\@topsepadd\@endpetrue}

You can see that the @endpe switch is set true as the last thing.

Let’s now return to our

\expandafter\endgroup\if@endpe\@doendpe\fi

So, we’ve just seen that the @endpe switch has just been set true as part of the execution of \endtrivlist, and—notice this—we are now checking its value before ending the group, so we do find that it is still true. At this point, the following tokens are still awaiting execution:

\engroup \@doendpe \fi \if@ignore \@ignorefalse \ignorespaces \fi

with a true conditional pending. So, the next thing that happens is that the current group is ended (note that this undoes your custom resetting of the meaning of \par, but this is not yet the explanation, because, at this point, you would expect \par to resume the meaning it had before the beginning of the center environment). Then \@doendpe is executed.

And here lies the explanation.

Indeed, \@doendpe is defined as follows (lines 4640–4645, that is, immediately below the definition of \@endparenv that we saw a minute ago):

\def\@doendpe{\@endpetrue
     \def\par{\@restorepar
              \clubpenalty\@clubpenalty
              \everypar{}\par\@endpefalse}\everypar
               {{\setbox\z@\lastbox}%
                \everypar{}\@endpefalse}}

We see that, when \@doendpe is executed, \par is redefined again.


That should suffice, for now. Of course, much more insight is needed to decide what to do next, and even to judge whether there is still some hope of pursuing your intent of figuring out an acceptable way of redefining \par that is, at the same time, sufficiently robust to survive all the twists and turns that this control sequence undergoes in the LaTeX kernel, and not only there. In case you are now thinking of moving your patch from \endtrivlist to \@doendpe, bear in mind that this macro sets the definition of \par that it sets for a very good reason, so you cannot simply overwrite it with your own. I regret to say that, like D.C., I lean toward seeing your idea as doomed to failure.

If I may, I’d like to conclude by suggesting a couple of questions that you should ask to yourself:

  1. What should happen to paragraphs contained in lists? Should they be treated in the same way as, or differently from, the other ones?

  2. Same question as 1, for paragraphs that constitute sectional headings.

(Deep breath.)

  • Thanks Gustavo for that explanation which helped me understand why patching \endtrivlist didn't work! – LaTechneuse Mar 18 '17 at 19:53
  • To answer the question what I actually want to achieve: I'd like to test whether a paragraph gets interrupted by a float. So my idea was to make \everypar, \par, and the float environment write stuff to the AUX file (using a counter for pars), then I can identify if a paragraph is interrupted by a float. With this I intend to write a solution to this problem: tex.stackexchange.com/questions/2650/… (removing \noindent of new pars after floats). I have a solution now and will post it after testing period. – LaTechneuse Mar 18 '17 at 19:56
  • @LaTechneuse: The question that you cite in your comments makes, in my not-so-humble opinion, no sense at all: there is no notion, in LaTeX, of “a paragraph that comes after a float”. Even if a paragraph follows a floating environment in the source file, this doesn’t have any relation with their mutual positioning in the printout; the float could end up to the top, or bottom, of the current page, or just as well on some of the following ones, perhaps also on a page by itself. – GuM Mar 19 '17 at 1:52
  • Of course. This is why the problem is about detecting the positioning in the printout not in the source code. Otherwise it would be very easy. From the perspective of the printed result, the problem is simple: My publishing company requests that new paragraphs after floating figures in the printout be started without indentation, while other new paragraphs do have indentation. There is no LaTeX mechanism to implement this and the whole LaTeX community is rather pessimistic about the possibility of solving this problem. (But I have a solution now, I will share it soon.) – LaTechneuse Mar 19 '17 at 9:32
  • @LaTechneuse: This looks like a task for the savepos module of the zref package (but mine is only a vague idea). – GuM Mar 19 '17 at 12:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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