7

I am looking for a way to peek at the next command within a command definition. Let me try to explain what I mean.

Consider that I have a command \cmd which prints something, say foobar. Now I'd like the command to only print foobar if the following command is not \nofoobar. That is

\cmd followed by some text or another command such as \cmd\foo should print foobar

However,

\cmd\nofoobar should not print foobar.

Ideally, it should also be the case that spaces are ignored. That is,

\cmd   \nofoobar should also not print foobar

I have no idea if that is at all possible but my guess is that there is some tex magic that allows to implement the functionality. Any help is much appreciated.

Following is a complete example.

\documentclass{article}

\newcommand{\cmd}{%
%If next command after cmd is \nofoobar print nothing, else print foobar
foobar}

\newcommand{\nofoobar}{%
}

\begin{document}

\cmd this should say foobar% prints foobar

\cmd\nofoobar this should not say foobar % does not print foobar

\cmd   \nofoobar ideally this should also not say foobar % that is, spaces should be ignored 

\end{document}
6

The underlying TeX primitive to peek ahead is \futurelet but that would not skip spaces, LaTeX wraps this in a space skipping loop as \@ifnextchar which does a \ifx test that the token is equal to the specified token so despite its name implying a "char" test, it can be used to test for any token.

For the particular case of \cmd the space skipping is not needed, as no space tokens are made after a command name but if \cmd took arguments and you needed to peek after \cmd{x} then this \@futurelet version comes in useful as it would skip spaces after the }.

\documentclass{article}

\makeatletter
\newcommand{\cmd}{\@ifnextchar\nofoobar{\@gobble}{foobar}}
\makeatother

\newcommand{\nofoobar}{nofoobar}


\begin{document}

\cmd this should say foobar% prints foobar

\cmd\nofoobar this should not say foobar % does not print foobar

\cmd   \nofoobar ideally this should also not say foobar % that is, spaces should be ignored 

\end{document}
  • note that strictly speaking this does not check for \nofoobar but for any command with definition nofoobar but if you give \nofoobar a unique-enough definition this comes to the same thing. – David Carlisle Jan 16 '17 at 12:19
  • 1
    Possibly use \kernel@ifnextchar to ensure you always get space skipping? – Joseph Wright Jan 16 '17 at 12:51
5

expl3 has a very powerful mechanism for peeking at the next token; you can optionally remove the next token or ignore spaces (or do both actions).

In this case you can use a function of the \peek_meaning family:

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\cmd}{}
 {
  \peek_meaning_remove:NF \nofoobar {foobar}
 }
\quark_new:N \nofoobar
\ExplSyntaxOff

\begin{document}

\cmd (this should say foobar)% prints foobar

\cmd\hfill (this should say foobar)% prints foobar

\cmd\nofoobar (this should not say foobar) % does not print foobar

\cmd   \nofoobar (ideally this should also not say foobar) % that is, spaces should be ignored

\end{document}

enter image description here

Here ignoring spaces is irrelevant because there is none in \cmd \nofoobar, but there's also

\peek_meaning_remove_ignore_spaces:NF

and of course you can have the NTF and NT forms for specifying, respectively, different actions in the true and false cases or just an action for the true case.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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