2

I'd like to extract and duplicate the contents of several rather arbitrary environments and repeat them at the end of my document. The extract package doesn't work for me because the environment contents are too complex. So the next thing I tried was etoolbox and environ:

\NewEnviron{foo}{%
  \xappto\mystorage{\BODY}%
  %% actual environment stuff
  \BODY
}

This approach works on paper for small toy examples, but on my real document I immediately run into exceeding the TeX capacity as \BODY is expanded.

What I therefore think I would like is a mechanism to expand only the first layer of \BODY. That is, I would like to replace it with the literal content that was given to the environment, if that makes sense.

I drew up a small demo-of-concept:

\documentclass{article}

\usepackage{etoolbox}
\usepackage{environ}

\def\mystorage{}

\NewEnviron{foo}{%
\def\xBODY{\expandonce\BODY}%
\xappto\mystorage{\xBODY^^J}
\BODY}

\newcommand{\quz}{Xyzzy}

\begin{document}
\begin{foo}
Hello \quz{} World
\end{foo}

\typeout{\mystorage}
\end{document}

What I'd like to happen here is that \mystorage contains Hello \quz {} World. But I haven't managed to make that work (by juggling various permutations of \expandafter and \protectify around); I either get \xBODY (which is of course meaningless at that point), or Hello Xyzzy{} World (which is expanded too much).

  • You could also just write it to an external file and then read it back. Are you going to answer this question, delete it or should we close it? – cfr Jul 11 '16 at 0:28
  • @cfr: I am genuinely curious about the answer. My problem still exists, because my environments have some non-trivial local definitions which doesn't make it easy to expand them fully at the first call, so I could still very much need a solution for the situation I describe. – Kerrek SB Jul 11 '16 at 0:39
  • Fair enough. But you mentioned that extract does now work for you, right? So what problem exactly are you trying to solve? Do you want the contents of the environment to be executed at the end of the document or are you trying to include the code in the document, after partial expansion or something else? – cfr Jul 11 '16 at 8:27
  • @cfr: The extract solution works, but is very brittle (e.g. I had to hack into the package to close the extraction output early in order to use it in the same run). I think that a solution based on explicitly programming the environments I care about would be more elegant and robust. Yes, I'd like to execute the contents again at the end of the same environment. – Kerrek SB Jul 11 '16 at 8:29
2

Your \mystorage is just accumulating the first level expansion of \body (plus some ^^J that you don't want unless writing to files)

You are being misled by the \typeout at the end as that fully expands the argument before showing it, so you get

Hello Xyzzy{} World

as you say, but if you change the \typeout to

\typeout{\meaning\mystorage}

then you see the actual definition of \mystorage shown as

macro:->Hello \quz {} World

so showing the result with two environments:

macro:->Hello \quz {} World\par Hello2 \quz {} World2\par 

if you use

\xappto\mystorage{\xBODY\par}

or more flexibly, use

\xappto\mystorage{\noexpand\begin{foo2}\xBODY\noexpand\end{foo2}}

producing

macro:->\begin {foo2}Hello \quz {} World\end {foo2}\begin {foo2}Hello2 \quz {} 
World2\end {foo2}

so then you can define the foo2 environment to do whatever you need with the saved texts.

  • I'd just use \xappto\mystorage{\expandonce{\BODY}}: no need to pass through \xBODY. – egreg Apr 22 at 23:00
  • @egreg yes I was aiming for minimal changes (I'd probably have used \g@addto@macro and some expandafters:-) – David Carlisle Apr 22 at 23:24

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.