1

Consider the following code that simply nests two lists using the \ForEach command:

\documentclass{article}
\usepackage{forarray}

\newcommand{\demo}[1]
{
\begin{itemize}
     \ForEach{.}{\item \thislevelitem}{#1}
\end{itemize}
}

\begin{document}
\demo
{
     1.
     \demo
     {
         21.
         22
     }.
     3
}
\end{document}

How should I modify the \demo command such that if I remove the . just before the 3, the output remains the same?

The motivation is to replicate an usual programming language syntax where statements are ended with . and control sequences ( such as \demo ) are enclosed between brackets (without a final .).

Feel free to use your preferred list processing tool instead of forarray but please try to avoid Expl3 syntax as long as possible.

7
  • 1
    By removing the . before the 3, how is it that you're going to distinguish between a continuation of a paragraph after a list and a new list entry for the outer list?
    – A.Ellett
    Jul 15, 2014 at 1:19
  • Whenever a demo group is closed, the following text should always be placed in a new item entry. Jul 15, 2014 at 1:52
  • I cannot write up a full blown answer right now, but given your latest comment, naively I would think of creating a counter to track the level of nesting. If the nesting is greater than zero, I would have the \demo macro throw out an \item. But, this approach has its own problems such as with \demo{1. \demo{21. 22}} where you wouldn't want an spurious \item showing up.
    – A.Ellett
    Jul 15, 2014 at 1:56
  • I'm not familiar with the forarray package; so, I don't know whether the macros it provides are expandable or not. If expandability is not an issue, you could use \@ifnextchar to test the next character to see whether or not to toss out an extra \item. If no one has posted their own solution to this later tonight, then I'll write up something that might work for you, but it won't be for several more hours.
    – A.Ellett
    Jul 15, 2014 at 1:59
  • 1
    You should define \newcommand\demo[1]{\@demo#1\@something} And then you can later use \futurelet to grab the token after the next and then run a test on whether you have two adjacent \@something. Now, if \@something is not defined as a macro, then that will just result in an error. Nevertheless, that's the main thrust of the idea for this naive approach.
    – A.Ellett
    Jul 15, 2014 at 2:07

1 Answer 1

1

Here's a rough draft for a solution. I believe this can be cleaned up a bit, but here's what I've come up with so far:

\documentclass{article}
\usepackage{forarray}

\makeatletter
\def\@demo@query{\relax}%%

\newcounter{@demo@level@cnt}
\newcommand{\demo}[1]{\@demo#1\@demo@query\@nil\@demo@follow@up}
\def\@demo#1\@nil{%%
  \stepcounter{@demo@level@cnt}%%
  \begin{itemize}
    \ForEach{.}{\item \thislevelitem}{#1}%%
}

\def\@demo@follow@up{%%
  \@ifnextchar\@demo@query
  {\@demo@close}
  {\@demo@continue}}

\def\@demo@continue{%%
  \@demo@close
  \ifnum\the@demo@level@cnt>0 %%
    \item
  \fi
}

\def\@demo@close{%%
  \end{itemize}%%
  \addtocounter{@demo@level@cnt}{-1}%%
}

\makeatother

\begin{document}
\demo
{
     1.
     \demo
     {
         21.
         22
     }
     3.4
}

\rule{\textwidth}{0.4pt}

\demo
{
     1.
     \demo
     {
         21.
         22
     }}


\rule{\textwidth}{0.4pt}

\demo
{
     1.
     \demo
     {
         21.
         22
     }   
}

\end{document}

The key is creating some wrapper code to get around the wrapper code introduced by forarray. Hence

\@demo#1\@demo@query\@nil\@demo@follow@up

The last command

\@demo@follow@up

will be followed by

\@demo@query

only if there is no further code to examine.

To assist in seeing what's happening consider the following moot code:

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{lmodern}

\makeatletter

\newcommand\demo[1]{\@demo#1?\@nil!}
\def\@demo#1\@nil{[\another{#1}]}
\def\another#1{<<#1>>}

\makeatother

\begin{document}
\ttfamily

\demo{1.\demo{21.22}3.4}\par
\demo{1.\demo{21.22}}

\end{document}

The macro \another wraps its arguments with << and >> in a manner similar to what forarrays macros do. The question mark plays the role of \@demo@query and the exclamation point that of \@demo@follow@up. As in the real solution above, ! only precedes ? when there is no continuation code for \ForEach to consider.

enter image description here

1

You must log in to answer this question.

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