3

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}
lockstep
  • 250,273
dikdirk
  • 141
  • 2
    Try #1 rather than \#1. – yannisl 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}. –  Feb 26 '12 at 21:50
  • Your original session expired and so your answer was posted under a new, but identical looking account. I merged both together now. You should consider registering your account to avoid such things in the future. Thanks. – Martin Scharrer Mar 02 '12 at 08:52

3 Answers3

4

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).

Ryan Reich
  • 37,958
  • 1
    ...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.... –  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. – yannisl 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
  • \documentclass{article} \usepackage{environ} \NewEnviron{patternn}[1] {% \textbf{Pattern} \BODY \newsavebox#1% \expandafter\lrbox#1 \BODY \endlrbox }

    \begin{document} \begin{patternn}{\aaa} test2 \end{patternn} \end{document}

    – dikdirk Feb 29 '12 at 22:14
  • If I remove the \BODY and just put some text there it works, but if for some reason I can't get it to work like this... do you guys have any suggestions? – dikdirk Feb 29 '12 at 22:15
  • 1
    @dikdirk Please add to your question and not in comments: reading code there is quite difficult. – egreg Mar 01 '12 at 00:07
1

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}
Martin Scharrer
  • 262,582
0

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}
lockstep
  • 250,273
dikdirk
  • 141
  • 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 02 '12 at 08: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 02 '12 at 08:56