3

This is follow up to a previous question that has been closed because it was treated wrongly.

Brief recap: let \newcommand{\foo}{foo}. Having \foo in text like so

test \foo bar

will omit the space after \foo which will result in test foobar, while

test {\foo} bar
test {\foo}.

produces test foo bar and test foo. which is exactly what I need.


While it's not possible to brace a macro before it's being parsed, there is a way to make space an active character.

Here's the solution by egreg that's close to what I'm looking for. However it uses an additional environment wrapper.

My question is how to apply the same technique of creating space active but only once, right after \foo? So that \foo takes one argument, parses it with respect to the spaces and puts #1 foo in the text maintaining the space if one was present.

1
  • 2
    any answer to your previous question woud be an answer to the general question about space after commands so closing as dup seemed OK to me Commented Apr 30, 2023 at 11:14

1 Answer 1

3

Here is one solution I can think of which uses just plain TeX.

\def\checkspace{\catcode`\ =12\relax\futurelet\csps\checkspaceA}
\def\checkspaceA{\catcode`\ =10\relax\if\space\csps\ \afterassignment\ignorespaces\expandafter\let\expandafter\csps\fi}

\def\foo{foo\checkspace}

test \foo   bar

test foo bar

test \foo.

\bye

The idea is like so: \checkspace first makes spaces other so that they are not skipped and can be \futurelet'd. Then we inspect the next token in \checkspaceA using \futurelet. \checkspaceA makes spaces space tokens again, and if the token we are inspecting is a space, then a \ is inserted.

The purpose of the rest of the code inside the conditional in \checkspaceA is to make sure that if \checkspace is followed by multiple spaces, all the spaces following the first are ignored. First I will explain the issue (to my understanding) so I can better explain my solution.

If we were to remove this code from \checkspaceA and do the following test:

\def\checkspaceA{\catcode`\ =10\relax\if\space\csps\ \fi}

test \foo bar

Then we would get test foo followed by a space, then an other space character (which looks like a slanted dash in cmr), then bar. The issue is that once we do \futurelet\csps\checkspaceA in \checkspace, the token following \foo is tokenized into an other space token, and left in the stream, and this is what creates the weird dash character.

So we can alter the code slightly to get rid of this:

\def\checkspaceA{\catcode`\ =10\relax\if\space\csps\ \expandafter\let\expandafter\csps\fi}

test \foo  bar

But now the issue is that since there are two spaces following \foo, the first one is correctly converted into \ by \checkspaceA. But the next space token really followed an other token, and is therefore not ignored. Doing \afterassignment\ignorespaces before the \let ensures that it is ignored.


This solution will not work for any character with catcode 10, and setting up the macros so that they work for other characters requires changing the catcodes of multiple characters and nesting \ifs.

In general I don't really see a reason to for these macros, I think it may just be simpler to follow your macros with an empty group. You almost certainly won't run into weird unintended side effects doing so.

I'm not 100% sure that my macros will always work, if there is an issue with them, feel free to tell me and I'd be happy to attempt to fix them.

1
  • Works perfectly as I expected. Thank you for such a detailed answer, I appreciate that.
    – antshar
    Commented Apr 30, 2023 at 16:33

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .