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.

I want to make a command that detects if the next token written in the document is a closing brace.

My best approach is to use the \@ifnextchar command. In fact, the following code:

\makeatletter
{
\@ifnextchar{\egroup}{yes}{no}
}
\makeatother

Does print yes. But when i try to define a command \demo in a .sty file as:

\newcommand{\demo}
{
\@ifnextchar{\egroup}{yes}{no}
}

and make the call:

{\demo}

It prints no. I suppose that this happens because LaTeX detects a "end of command" token before returning to the document. Anyway, I would like to know the actual reason of why this happens, and how should I define the \demo command for printing yes in the last example.

edit:

In a blank document it actually prints yes. This is my minimal working example where it prints no:

\documentclass[a5paper]{book}

\usepackage{xparse}

\NewDocumentCommand{\wrapper}{ >{\SplitList{.}} m }
{
\begin{itemize}
\ProcessList{#1}{\entry}
\end{itemize}
}

\newcommand{\entry}[1]
{
\item \begin{math} #1 \end{math}
}
\makeatletter
\newcommand{\demo}{\@ifnextchar{\egroup}{yes}{no}}
\makeatother

\begin{document}

\wrapper{a.b.{\demo}.d} prints no
but {\demo} prints yes


\end{document}

edit 2:

I just noticed that in my project, detecting that \demo is the last one within a \wrapper could be enough. So:

\wrapper{\demo.\demo}

should print no first and then yes. Now that I look at it this way, I'm sure it has to be another way to get this information easier.

share|improve this question
1  
I get yes. Can you show a minimal example? –  egreg Apr 26 at 15:59
    
(a) Your real world macro \demo should not contain any code between \@ifnextchar with its three arguments and the end of the macro. Otherwise \@ifnextchar would just see the first token of the code. (b) \@ifnextchar gobbles following spaces (for example, the space in the definition by the line end). If spaces matter, then \ltx@ifnextchar@nospace of package ltxmcds can be used. –  Heiko Oberdiek Apr 26 at 16:06
    
The braces around \demo are stripped off by effect of \SplitList. –  egreg Apr 26 at 16:29
    
A much slower routine needs to be used if you don't want the braces are stripped off. Can you tell why you want to do this? –  egreg Apr 26 at 16:36
1  
@A.Ellett That's a general TeX feature: when arguments are grabbed (delimited or undelimited) a pair of braces is stripped off unless, in the delimited case, they would leave unbalanced braces. –  egreg Apr 26 at 17:22

2 Answers 2

up vote 4 down vote accepted

If all you want is that \demo prints yes if it's the last item in the list, then this should work:

\documentclass[a5paper]{book}

\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\wrapper}{ m }
 {
  \begin{itemize}
  \azpillaga_wrapper:n { #1 }
  \end{itemize}
 }

\NewDocumentCommand{\demo}{ }
 {
  \azpillaga_demo:
 }

\seq_new:N \l__azpillaga_input_seq
\tl_new:N \l__azpillaga_last_tl
\bool_new:N \l__azpillaga_last_item_bool
\cs_new_protected:Npn \azpillaga_wrapper:n #1
 {
  \bool_set_false:N \l__azpillaga_last_item_bool
  \seq_set_split:Nnn \l__azpillaga_input_seq { . } { #1 }
  \seq_pop_right:NN \l__azpillaga_input_seq \l__azpillaga_last_tl
  \seq_map_inline:Nn \l__azpillaga_input_seq { \entry{##1} }
  \bool_set_true:N \l__azpillaga_last_item_bool
  \entry {\tl_use:N \l__azpillaga_last_tl }
 }
\cs_new:Npn \azpillaga_demo:
 {
  \bool_if:NTF \l__azpillaga_last_item_bool
   {
    yes
   }
   {
    no
   }
 }
\ExplSyntaxOff

\newcommand{\entry}[1]
{
\item \begin{math} #1 \end{math}
}

\begin{document}

Not at the end:
\wrapper{a.b.\demo.d}

At the end:
\wrapper{\demo.\demo}

\end{document}

enter image description here

share|improve this answer
    
This is definitively a working answer. It's important to keep my document free of expl3 syntax. Can someone build an alternative? –  Martin Azpillaga Apr 26 at 17:33
    
@MartinAzpillaga If you use xparse you have expl3 anyway. –  egreg Apr 26 at 17:35
    
At this moment, I know nothing about expl3. As I mentioned above, this code is part of a more complicated structure which I would be unable to switch to expl3 right now. If I can't get a non-expl3 answer, I'll probably post a new question with the whole structure so a full restructuring can be made. –  Martin Azpillaga Apr 26 at 17:52
    
Sorry, you can't do this with xparse only. –  egreg Apr 26 at 17:58
    
Then I think this is the best answer. Good job :) –  Martin Azpillaga Apr 27 at 12:16

Though this has already been answered by @egreg , here's a solution that superficially avoids expl3: as already mentioned by egreg, since xparse is built on expl3 there really is no avoiding it.

If all you want to do is to be able to detect whether \demo has been passed as the last item in a list, this should work:

\documentclass[a5paper]{book}
\usepackage{xparse}

\makeatletter

\def\mylastitem{\relax}

\NewDocumentCommand\wrapper{ m }
  {\ae@wrapper{#1\mylastitem}}

\NewDocumentCommand{\ae@wrapper}{ >{\SplitList{.}} m }
{\begin{itemize}
 \ProcessList{#1}{\entry}
 \end{itemize}}

\newcommand{\entry}[1]{\item \begin{math} #1 \end{math}}

\newcommand\demo{\@ifnextchar\mylastitem{\textit{yes}}{\textit{no}}}

\makeatother

\begin{document}

\wrapper{acd.b.{\demo}.d} prints \textit{no}

\wrapper{acd.b.c.\demo} prints \textit{yes}

\end{document}

However, I should point out that the community here will most likely frown on this sort of approach since I'm mixing the older style @ notation with an implicit expl3 style package. Nevertheless, if you still feel the need to know how to get this to work without having to actually write expl3 code yourself, the above should do the trick for you.

share|improve this answer

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.