# How can I collect the contents of a LaTeX environment in a macro without the grouping?

It's a bit of a long story as to why I need to do this, but please bear with me. I have a fairly complicated custom class which expects documents to begin with a command:

\coverandabstract{Abstract text goes here}


What this does is lay out a (one column) cover page, basically a custom maketitle, then switches to two column layout with different page dimensions on page two, beginning with an abstract that spans both columns.

Now, I want to be able to draft the document in Markdown and convert to this class (and other formats) via Pandoc. The most cross-format way of representing the abstract is as a blockquote, which gets converted to a quote environment.

\begin{quote}
Abstract text goes here
\end{quote}


So what I need to do is find a way of converting the first, and only the first, quote environment into the \coverandabstract command.

Now one way of doing this would be to use the environ package:

\usepackage{environ}
\let\oldquote=\quote
\let\endoldquote=\endquote
\makeatletter
\renewenvironment{quote}%
{\Collect@Body\coverandabstract}%
{\let\quote=\oldquote
\let\endquote=\endoldquote}
\makeatother


The problem is that the class is based on memoir, and changing the page layout means using \checkandfixthelayout. This doesn't work properly if called within an environment, probably as a result of the grouping. This means the above technique ruins the layout for the remainder of the document.

So is there a way of passing the contents of an environment to a command without having it wrapped in a TeX group?

If you stick with environ you can lift the code out of the group with \aftergroup

\documentclass{article}

\def\coverandabstract#1{\twocolumn[#1]}

\usepackage{environ}
\let\oldquote=\quote
\let\endoldquote=\endquote
\let\quote\relax
\let\endquote\relax

\NewEnviron{quote}%
{\global\let\tmp\BODY\aftergroup\docoverandabstract}

\def\docoverandabstract{%
\let\quote=\oldquote
\let\endquote=\endoldquote
\coverandabstract{\tmp}}

\begin{document}

\begin{quote}
Abstract text Abstract text Abstract text
Abstract text Abstract text Abstract text
Abstract text Abstract text Abstract text
\end{quote}

\texttt{\meaning\quote}

a a a a a a a a a a a a a a a a a a
a a a a a a a a a a a a a a a a a a
a a a a a a a a a a a a a a a a a a

\end{document}


I'd say

\let\oldquote\quote
\let\oldendquote\endquote
%% the following to please environ
\let\quote\relax
\let\endquote\relax

\NewEnviron{quote}{%
\xdef\dolatercoverandabstract{%
\noexpand\coverandabstract{\unexpanded\expandafter{\BODY}}%
\unexpanded{\let\quote\oldquote\let\endquote\oldendquote}%
}\aftergroup\dolatercoverandabstract}


Without \unexpanded, the definition of the new quote environment should be

\NewEnviron{quote}{%
\expandafter\gdef\expandafter\dolater\expandafter{%
\expandafter\coverandabstract\expandafter{\BODY}%
\let\quote\oldquote\let\endquote\oldendquote
}\aftergroup\dolater}


After a lot of head scratching and failed experiments, I finally came up with a hack that does the trick.

\let\oldquote=\quote
\let\endoldquote=\endquote
\makeatletter
\def\quote#1\end{%
\end{quote}%
\coverandabstract{#1}%
\let\quote=\oldquote
\let\endquote=\endoldquote
\@gobble}
\makeatother


The first two lines save the normal definition of the quote environment.

What the (re)definition does is nullify the effect of \begin{quote}, then extract everything between \begin{quote} and the next \end (it means not using another environment inside this one, but that's fine.) It then immediately closes the quote environment, leaving us back at the top level. I can then put the collected content in the \coverandabstract command (which now operates as intended) and revert the quote environment back to its original definition.

This just leaves a stray {quote} token for TeX to parse (from \end{quote}), so I remove it with \@gobble (hence the \makeatletter and \makeatother).