# Can I make a command not gobble spaces?

(I'm using ConTeXt, but I suspect the answer will lie in plain TeX.)

I've created an environment that takes one argument myBufferName, and stores its contents in a buffer of that name. Unfortunately, all spaces after the argument are gobbled, and I don't know how to stop this properly. The usual gobble-stoppers, {} and \, end up in the buffer verbatim if I put them after \dostartbuffer.

\startluacode
-- Print contents of buffer b to stdout and tmp.txt for inspection
function printbuffer(b)
-- Once to stdout ...
print('====')
print(buffers.getcontent(b))
print('====')

-- ... and once to tmp.txt.
jan = io.open('tmp.txt', 'w')
jan:write(buffers.getcontent(b))
jan:close()
end
\stopluacode

% This environment stores its contents in a custom-named buffer.
% (The #1 merely allows whitespace, like this: \startMyBuffer [name])
\def\startMyBuffer#1[#2]
{% Store the name --- we'll need it when defining stopMyBuffer
\def\myBufferName{#2}
% ConTeXt macro that defines the \start... and \stop... commands.
\dostartbuffer[#2][startMyBuffer][stopMyBuffer]}

%% % Hack I currently use: a dot at the end of the definition.
%% \def\startMyBuffer#1[#2]
%%     {\def\myBufferName{#2}
%%      \dostartbuffer[#2][startMyBuffer][stopMyBuffer].}
%% %                                                   ^
%% %                                                   |
%% % I later remove the dot using Lua.

% On closing the buffer, print its contents.
\def\stopMyBuffer
{\ctxlua
{printbuffer('\myBufferName')}}

% Test it. You'll see the first line loses its leading whitespace :-(
\starttext
\startMyBuffer[myNameIsNobody]
Andra moi ennepe,
mousa,
polutropon.
\stopMyBuffer
\stoptext


When you try running it, this gives

Andra moi ennepe,
mousa,
polutropon.


as the buffer's contents.

-

You define the macro as

\def\startMyBuffer#1[#2]
{....}


To avoid the macro eating spaces, use

\def\startMyBuffer#1[#2]%
{...}


(Note the % at the end. You also have a trailing whitespace at the end of the next line. Thus, a proper definition of the macro is

\def\startMyBuffer#1[#2]%
{% Store the name --- we'll need it when defining stopMyBuffer
% ConTeXt macro that defines the \start... and \stop... commands.
\dostartbuffer[#2][startMyBuffer][stopMyBuffer]}


If you don't want to worry about all this, use \starttexdefinition ... \stoptexdefinition instead.

\starttexdefinition startMyBuffer #1[#2]
% Store the name --- we'll need it when defining stopMyBuffer
\def\myBufferName{#2}
% ConTeXt macro that defines the \start... and \stop... commands.
\dostartbuffer[#2][startMyBuffer][stopMyBuffer]
\stoptexdefinition

-
Tried them both, they both work a treat. Thank you! – Esteis Feb 19 '12 at 22:04

The general syntax of \def is

\def<name><parameter text>{<replacement text>}


, where <parameter text> is matched against input. The parameter text can contain parameter tokens (#1, #2, …) and other tokens, for example, #1[#2]abc. Other tokens are matched exactly against input — in this example, if TeX fails to find a sequence <something>[<something>]abc, it will stop with an error. After a match has been found, the <something> parts will be taken as macro parameters per parameter text definition, but the other matched tokens will be simply eaten. In your case the parameter text of \startMyBuffer contains space after [#2], thus it will be also matched and eaten.

Look at the output of this Plain TeX document to see the difference:

\def\readsome#1\relax{#1'}
\def\a[]

\a[]
test\relax
\b[]
test\relax

\bye


Conclusion: don't put extraneous symbols in macro parameter text. For Plain TeX/LaTeX, let { follow immediately after all parameters have been specified; for ConTeXt, put a % after the parameter text to ignore the newline and the following space.

-
In ConTeXt, the standard style is to add a % on the \def line and put { on the next line. – Aditya Feb 15 '12 at 17:21
@Aditya: Thanks, good to know. – Andrey Vihrov Feb 15 '12 at 18:13

I'm not sure if I understand your question correctly, but you seem to indicate that you don't want TeX to gobble whitespace. If that's what you're after, check out the commands \obeyspaces (Plain TeX) and \obeywhitespace` (eTeX).

-