Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

A standard way to grab and store a short text (say, a title of a document) is to use something like

\def\title#1{\def\@title{#1}}.

But if the content to be stored is longer (say, an abstract}, I guess it is considered more elegant to specify it by something like

\begin{abstract}
  ...
\end{abstract}

on the user side.

So, the question is: what techniques are available to do something like this? (Some that spring to my mind immediately are: use a \vbox, use delimited arguments, use the environ LaTeX package, use ConTeXt \grabbufferdata (if I am not mistaken as to the name of that macro)...)

I'd be delighted to see all kinds of answers, for various engines (Knuthian vanilla TeX, eTeX, luaTeX) and formats (plain TeX, LaTeX2e, LaTeX3, ConTeXt).

share|improve this question
1  
To be honest, if you are planning to "grab" the environment content in a macro or token register, I'd advise to use the normal "control sequence" syntax. It looks less elegant in the document, but is more honest and less prone to provoke misunderstandings. An environment is supposed to have the semantics that something is executed at the beginning, then the content is executed and then something is executed at the end. Changing that will confuse especially new users, because they can't understand why they can't use \verb inside or whatever. –  Stephan Lehmke Sep 4 '12 at 3:43
2  
Good point. However, I can imagine at least two situations when this is not the case: (i) backward compatibility with existing classes/packages (the case of abstract) and (ii) situations when you want to do both: typeset and store some material for later reuse. And I wouldn't care too much about \verb, if you need to use it, you are probably writing about TeX itself, and that means that you're not a newbie;). (\url is a problem, though.) –  mbork Sep 4 '12 at 8:27

5 Answers 5

The collect package; a little example (defining an environment to collect text and format it between rules and using \section):

\documentclass{article}
\usepackage{collect}
\usepackage{lipsum}

\definecollection{test}
\makeatletter
\newenvironment{atest}[1]
  {\@nameuse{collect}{test}{\par\nobreak\noindent\hrulefill}
    {\par\nobreak\noindent\hrulefill\par\bigskip}
    {\section{#1}}
    {}%
  }
{\@nameuse{endcollect}}
\makeatother

\begin{document}

\begin{atest}{example one}
\lipsum[2-3]
\end{atest}

\begin{atest}{example two}
\lipsum[2]
\end{atest}

\lipsum[1-6]

\includecollection{test}

\end{document}

enter image description here

share|improve this answer
    
Thanks, I didn't know about this package! –  mbork Sep 4 '12 at 8:29

Straight LaTeX2e:

\newsavebox{\myabstractbox}
\newenvironment{myabstract}{\lrbox{\myabstractbox}}{\endlrbox}

Extract the contents with

\usebox{\myabstractbox}
share|improve this answer
2  
This doesn't store the text, but only its printed representation. –  egreg Sep 4 '12 at 6:31
1  
@egreg: yes, but sometimes this is perfectly fine. –  mbork Sep 4 '12 at 8:27

In ConTeXt, \grabbufferdata is a low-level command that is only useful to module writers. At user level, buffers should be used to grab and store contents. For example, store the contents using

\startbuffer
    Whatever
\stopbuffer

and retreive them using:

\getbuffer

You may also typeset the contents using

\typebuffer

which is useful when you want to include verbatim material in tables and footnotes.

Buffers may be thought of as a clipboard for copy-pasting content; in fact, as named clipboard, which is useful when you want to repeat material in a document like a presentation or build metapost figures in steps. To get named buffers, simply store content using

\startbuffer[anything]
    This is a named buffer
\stopbuffer

and retrieve it using

\getbuffer[anything]

or

\typebuffer[anything]

Buffers are more robust than grabbing content using boxes because you do not need to care about catcodes while grabbing content. (Of course, you need to worry about them when retreiving content).

\startbuffer
  A C file starts with \type{#include<stdio.h>}.
\stopbuffer

\getbuffer

works fine even though the content has a #. For this reason, buffers are used when you want to process some XML inline in a regular TeX document.

Buffers can also be nested. For example:

\startbuffer[one]
   Buffer one
   \startbuffer[two]
      Buffer two
   \stopbuffer
\stopbuffer


\getbuffer[one]
\getbuffer[two]

(of course, buffer two is only available after buffer one has been retreived).

In MkIV, \startbuffer and \stopbuffer can be on the same line

\startbuffer[line] #line \stopbuffer
\typebuffer[line]

And finally, the contents of a buffer are available at the Lua end (as the content is stored in memory). Use the Lua function buffers.getcontent('name') to access the contents of the buffer named name.

Of course, like any other ConTeXt macro, you may define your own version of buffers.

\definebuffer
  [grabcontent]
  [
    before=...,
    after=...,
  ]

and then use them as regular buffers.

\startgrabcontent
  A # B C
\stopgrabcontent

\typegrabcontent

The before and after keys are used with \getgrabcontent.

Since buffers don't care about their content, they are an excellent comment environment. In fact, the hiding environment in ConTeXt is defined as a buffer.

\setupbuffer
  [\v!hiding]
  [\c!before=,
   \c!after=]
share|improve this answer
    
I've always wondered about the implementation here: I assume a toks holding material grabbed verbatim? (Perhaps that would make a good question!) –  Joseph Wright Sep 4 '12 at 6:49
    
@Aditya: thank you so much, I expected your comprehensive answer about ConTeXt;). As usual, I could learn from it... –  mbork Sep 4 '12 at 8:31
    
@JosephWright: I'm not sure, but I guess that it's some lua trickery, and I'm pretty sure that in MkII it was writing to a temporary file. –  mbork Sep 4 '12 at 8:32
    
Indeed, in MkII data was written to temp files. The implementation was similar to data grabbing macro from fancyverb package: data was parsed line by line and the grabbed string was compared with \stopbuffer. (That was the reason that \stopbuffer had to be on a line of its own). In MkIV, the implementation is Lua based, but it is relatively simple (effectively same as plain TeX answer of egreg, but ConTeXt first changes the catcode table to vrbcatcodes and uses a configurable stopper; I really don't understand why nested buffers work). –  Aditya Sep 4 '12 at 15:18

LaTeX

If you just want to store the text in form of tokens, like \title does, then you can do it with environ:

\usepackage{environ}
\NewEnviron{sabstract}{\global\let\@sabstract\BODY}

The environment's content is (locally) stored in the macro \BODY, so globally letting \@sabstract to it will do the same as \title does with \@title.

\begin{sabstract}
This is it.

With two paragraphs.
\end{sabstract}

Plain TeX

\catcode`@=11
\long\def\sabstract#1\endsabstract{\def\@sabstract{#1}}
\catcode`@=12

\sabstract
This is it.

With two paragraphs.
\endsabstract
share|improve this answer

Wheee another one for the #-rule:

\documentclass{article}
\def\dosomething{inside,}
\def\dosomethingelse{and outside the group}
\def\foo#{\bgroup\dosomething\aftergroup\dosomethingelse\let\next= }

\begin{document}
\foo{
  \verb|bar|

  \verb|baz|
}
\end{document}
share|improve this answer
2  
I think you have it the wrong way round. The OP wants to know how to turn an environment into a macro argument, and you are showing how to turn a macro argument into an environment ;-) –  Stephan Lehmke Sep 4 '12 at 17:50
1  
@StephanLehmke: That \vbox threw me off. Still, I think it's nice enough to mention. –  morbusg Sep 5 '12 at 3:53

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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