4

Because I write my own document class (okay, I try to ...), this question bothers me for weeks as there are many situation, in which I need something like this.

Is there a way to test, if the next token list in the input stream is command \foo? I didn't found anything like this (or I didn't recognize it), neither in the web nor in the expl3 documentation. For example, I want to realize something like this:

\DeclareDocumentCommand \test {  } {%
  \if_next_tl:NTF \emph {   % This function doesn't exist!
    % Do something if true
  }{
    % Do something if false
  }
}

So when I write

Bla \test Bla Bla

the false code is executed, and when I write

Bla \test \emph{Bla} Bla

the true code is executed.

I know there are LaTeX3 functions like \peek_after:Nw, \peek_charcode:NTF and TeX macros like \@ifnextchar, but I don't understand how to use them in this case. I think it would be the best to use LaTeX3 functionality for this. And maybe, I am completely wrong and this is not the correct attempt to solve things in LaTeX.

In addition: Is there a similar way to test, if there follows an environment foo in the input stream?

Background

This is an simplified example where I could use this: I have a command \exercise, which typesets something like an headline with a following vertical space. If "normal" text follows after \exercise, this looks like it should. But if I add an enumeration after \exercise, the vertical space looks too small---although it is the same. I don't know why, but maybe because of the space between the items (it's all about perception and a optical correction). That's why I want to add a very small additional space after the heading in \exercise, if it's followed by an enumeration. So what I want to realize is something like "conditional spacing". Here's an example:

Code

\documentclass{scrartcl}

\usepackage[ngerman]{babel}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}

\usepackage{lipsum}
\usepackage{xparse}
\usepackage{noindentafter}

\DeclareDocumentCommand \exercise {  } {%
  \vspace{\baselineskip}
  \noindent\textsf{\bfseries\Large Exercise}
  \vspace{0.5\baselineskip}
  \NoIndentAfterThis
}

\begin{document}

\exercise

\lipsum[1]

\begin{enumerate}
  \item One
  \item Two
  \item Three
\end{enumerate}
\lipsum[1]

\exercise

\begin{enumerate}
  \item One
  \item Two
  \item Three
\end{enumerate}

\end{document}

Document

Here's the result. In my opinion, the space after the second "Exercise" is a little bit too small. So I want to add some space after \exercise, if it is followed by an enumeration.

Example document

  • From what I understand, \@ifnextchar can be extended arbitrarily. Normally one would use e.g. \@ifnextchar[ for optionals. Why not use \@ifnextchar\foo? (Untested, but I remember @egreg mentioned something like this.) – 1010011010 Aug 15 '14 at 12:03
  • Mea culpa! Okay, I didn't find that. Thank you. As you said, most examples of \@ifnextchar are dealing with \@ifnextchar[. But is there a "modern" LaTeX3 equivalent to \@ifnextchar? And what about testing if there is an environment foo following? – dawu Aug 15 '14 at 12:09
  • 3
    I think you want one of the \peek_meaning(...):NTF macros (page 59 of interface3.pdf). – You Aug 15 '14 at 12:32
  • 1
    This sounds like something we're really not trying to encourage in LaTeX3 development: can you give some idea of why the behaviour of your document command is dependent on the following token? (We do know we want 'design level' relationships between document elements: not yet implemented! However, I suspect that is not what you are after.) – Joseph Wright Aug 15 '14 at 12:43
  • Indeed, it is possible that I intend to do something basically wrong. I have an command \exe which typesets something like a headline. The normal usecase is to write normal text after \exe. But sometimes you need an environment graphicscol If (and only if) this environment follows after \exe, there should be inserted some additional vertical space. – dawu Aug 15 '14 at 13:11
3

The answer ended up being just \addvspace rather than \vspace.

By the way, in expl3 \peek_after:Nw \somecommand saves the next token after \somecommand into \l_peek_token then executes \somecomand, which might do checks on \l_peek_token.

Better would bee \peek_meaning:NTF \emph { True } { False } which compares the next token after { False } with \emph, giving true in case it's \emph.

1

There is a TeX primitive which exactly does what you want, it is called \futurelet. Let me quote the TeXbook:

TeX also allows the construction \futurelet\cs〈token₁〉〈token₂〉 which has the effect of \let\cs=〈token₂〉〈token₁〉〈token₂〉.

This primitive does not quite do exactly what you want, to begin with it has no clue what LaTeX is, let alone environments. Nevertheless this primitive implements the basic look-ahead mechanism you need to implement a predicate testing if some environment is coming next in the input stream.

Why it is a bad idea to do something like this in LaTeX

TeX (the program, not plain TeX nor LaTeX) is a typesetting language with a powerful macro system and LaTeX is a markup language built atop TeX the program. We may say that \futurelet does not really belongs to the language defined by LaTeX, it is still here because it was whether removed nor hidden, but this is not something that you are expected to use. If you do so, you are explicitly voiding the warranty of LaTeX, so to say.

Difficulties bound to look ahead mechanisms

If you want to try \futurelet, you need to write your macros with great care otherwise they will be very brittle. Also, you want to be sure to review the following topics:

  • When catcodes are assigned to tokens
  • How tokens are compared by TeX with \if
  • How token catcodes are compared by TeX with \ifcat
  • How tokens sequences are compared by TeX with \ifx

Note: Actually, \ifx compares the replacement text of two macros, but its most important use case is to compare two macros which are \edef-d versions of token registers.

Warm up challenges

If you are interested by learning to use \futurelet you can take up the three following challenges:

  1. Write a version of \ignorepaces which looks into input statements.
  2. Write a \futuretoks\to#1\then#2 macro which stores the token given by \futurelet in the token register #1 and gives control to #2. Does it work well with spaces and newlines?
  3. Write a package which allows to define macros taking arguments like \hbox and \hfill do.

If you take 3 up, you can compare it with the getoptk package found in tex/plain/contrib/getoptk. Besides the guide to the macros I wrote an article in TuGboat describing their implementation.

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.