Making an environment that stores stuff in a box

Im trying to make make an environment that both: displays text and stores stuff in a box for later use. For this I need to use the input argument of the enviroment to manufacture a command name, i.e. \#1. For some reason I can't get this to work in latex.

\documentclass{article}
\newenvironment{testenv}[1]
{   \textbf{Test Environment}
\newsavebox{\#1}
\begin{lrbox}{\#1}
}
{
\end{lrbox} \usebox{\#1}
}

\begin{document}

\begin{pattern}{aaa}
test
\end{pattern}

\usebox{\aaa}

\end{document}

-
Try #1 rather than \#1. –  Yiannis Lazarides Feb 26 '12 at 20:32
Also, you might want to check the environ package. –  mbork Feb 26 '12 at 20:44
No, the problem (one of them) is trying to "construct a command name" by attaching a backslash. For that you need the \csname...\endcsname construction, but since you are using LaTeX, I suggest that you avoid this and just require the argument to your environment to be a command name in the first place. –  Ryan Reich Feb 26 '12 at 20:57
@RyanReich: also, one might consider using etoolbox and its \csdef and similar commands (though in this particular case it might not work anyway). Maybe expl3? –  mbork Feb 26 '12 at 21:00
You cannot refer to the positional parameters in the second required argument of the\newenvironment command. You have to define a command in the first required argument and use it in the second: newenvironment{textenv}[1]{define here. more stuff}{use here}. –  Marc van Dongen Feb 26 '12 at 21:50

Try this:

\documentclass{article}
\newenvironment{pattern}[1]
{%
\newsavebox#1%
\lrbox#1
}
{%
\endlrbox
}

\begin{document}

\begin{pattern}{\aaa}
test
\end{pattern}

\usebox{\aaa}

\end{document}


The big problem with your code is that you can't construct a macro name by attaching a backslash to unknown text (like #1). This has to do with the way TeX reads its input; by the time it sees what is in #1, it has stopped constructing names. You can fix this by writing \csname#1\endcsname, but that has technicalities that aren't worth dealing with since you can just require that the argument to the pattern environment be a macro name in the first place.

A minor change I would make (other than the fact that it does not compile as written because you make a definition for testenv but use the pattern environment) is to use \lrbox and \endlrbox directly rather than the \begin and \end constructions. This allows LaTeX to correctly track that it is your environment that is open, rather than the lrbox environment you are using inside it. (If you screw up, it would tell you that lrbox was not correctly closed, which is technically true but not always informative if you did not explicitly write lrbox in your document).

-
...additionally, #1 is unknown at \end{pattern}. –  Werner Feb 26 '12 at 21:11
I think the challenge is typesetting the box in the environment.... –  Marc van Dongen Feb 26 '12 at 22:43
Ryan -- I think is preferable to use \csname..endcsname and define a name for the box say box@#1 at the first part of the environment, then you can use it as the OP wanted it. The name will escape to the end part of the environment. –  Yiannis Lazarides Feb 26 '12 at 22:44
Thank you all for the responses, I'm really learning a lot about how this macro/environment stuff works. I combined your answers into the following: –  dikdirk Feb 29 '12 at 22:12

Thank you all for the responses, I'm really learning a lot about how this macro/environment stuff works. I combined your answers into the following and got it working exactly how I wanted! :)

\documentclass{article}

\usepackage{environ}

\NewEnviron{patternn}[1]

{ \textbf{Pattern} \BODY \newsavebox{#1}  \global\sbox{#1}{\BODY} \usebox{#1}}

\begin{document}

\begin{patternn}{\aaa}
test
\end{patternn}

And now try again:
\usebox{\aaa}

\end{document}

-
You should watch the spaces in your source code. A space or line break after } or { will lead to a space in the document, which is normally not wanted. Spaces after macros however are deleted automatically. –  Martin Scharrer Mar 2 '12 at 8:50
Note that environ environments are not real environments, but pseudo-environments, i.e. they are actually handled like a macro internally. Therefore you loose all benefits of real environments, like the efficiency that not the whole content must be read at once and the support for verbatim and similar special code. –  Martin Scharrer Mar 2 '12 at 8:56

The problem with box-saving environments is that all code inside the environment is usually local. The 'lrbox' environment actually breaks out of its own group to ensure that the box assignment is part of the surrounding scope. This makes including it as part of other environments difficult. Using the "plain-TeX style" \lrbox .. \endlrbox causes issues because of the special group handling.

Either you replicate the internal code of lrbox (see the file latex.ltx) or you use global assignments, which will earn you minus points in the B-mark but is much simpler to implement and might be acceptable in your case. You can use the lower-level TeX code (\setbox with \bgroup and \egroup instead of braces) to store the environment content. You need to add the internal color grouping statements to ensure that all color macros, if any, are properly stored in the box as well.

\documentclass{article}

\makeatletter
\newenvironment{patternn}[1]{%
\par % I think you should start a paragraph first, but it's up to you
\textbf{Pattern}%
\newsavebox{#1}%
\global\setbox#1\hbox\bgroup\color@setgroup
}{%
\color@endgroup\egroup
\usebox{#1}%
}
\makeatother

\begin{document}

\begin{patternn}{\aaa}
test
\end{patternn}

And now try again:
\usebox{\aaa}

\end{document}

-