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'm writing macros to typeset lists in plain TeX. Please can you suggest some examples of macros for numbered lists? I'd prefer examples from "living code", from CTAN packages and so on. But any kind of help would be appreciated.

I wrote working code, but a bit cumbersome, so I'm looking for examples of elegance and functionality.


[edit] Joseph Wright said that it might be handy to show what I've done and outline what the issues I have are. Well, I got no real issues, but concerns about the expandability and maintainability of the code. As I said the code works but it is complicated and the macros are too long and devoid of elegance.

Well, the goal is to typeset a numbered list like this.

1. gjkjhg
2. jhlujh sch
  2.1. fhwoiuhf
  2.2. eryqwo uhf u
  2.3. sdiuahx iuhd
    2.3.1. xph  p
    2.3.2. erofhx efh
3. owhd xpqwo

the interface will be like this

\beginenumerate
  \item gjkjhg
  \item jhlujh sch
  \beginenumerate
    \item fhwoiuh
    \item eryqwo uhf u
    \item sdiuahx iuhd
    \beginenumerate
      \item xph  p
      \item erofhx efh
    \endenumerate
  \endenumerate
  \item owhd xpqwo
\endenumerate

so I will use the following variables:

\newcount\c@listlevel \c@listlevel\z@
\newcount\c@item
\newcount\countlev@i % number of last item in every nesting level
\newcount\countlev@ii
\newcount\countlev@iii % max three levels of nesting
\def\init@str{} % the label of every item

Now follow the macros.

\def\beginenumerate{\begingroup
  \ifnum\c@listlevel=3\relax\else\advance\c@listlevel\@ne\fi

  \ifnum\c@listlevel=\@ne
    \vskip.5\baselineskip
    \toks0=\everypar\fi % \everypar will change later, so I save it.

  \ifnum\c@listlevel>\@ne
    \edef\init@str{\init@str\number\c@item.}\else
    \edef\init@str{}\fi

  \c@item\z@

  \def\item{%
    \edef\@countlevstr{\romannumeral\c@listlevel}% may be i, ii or iii
    \c@item\csname countlev@\@countlevstr\endcsname% \c@item is loaded from the right \countlev@...
    \advance\c@item\@ne
    \csname countlev@\@countlevstr\endcsname\c@item% so \countlev@... records the number of last item in every nesting level

    \dimen0\parindent
    \multiply\dimen0\c@listlevel

    \ifvmode\else\par\fi

% if an \item has more than one paragraph only the first one have to be preceded by a label;
% so \@itemlabel redefine itself the first time is expanded.
    \def\@itemlabel{%
      \llap{\init@str\number\c@item.\quad}%
      \gdef\@itemlabel{}}%

    \everypar{\setbox0\lastbox
      \hangindent\dimen0 \hangafter\z@
      \@itemlabel}}}% end of \beginenumerate

\def\endenumerate{%
  \ifnum\c@listlevel=\z@\else
    \advance\c@listlevel\m@ne
  \fi
% if \init@str is 3.5.4. has to become 3.5.
  \def\next@str##1.##2.;{##1}%
  \ifnum\c@listlevel>\@ne
    \edef\init@str{\expandafter\next@str\init@str;.}%
    \else\edef\init@str{}\fi

  \ifnum\c@listlevel=\z@
    \vskip.5\baselineskip
    \everypar=\toks0
  \fi
  \endgroup}

Mr. Wright, have you some idea on how to make the code a bit better than it is? Many Thanks.

share|improve this question
    
Plain TeX tends to imply no packages (or at least very few: eplain for example might be acceptable to plain users). So you will probably need to 'roll your own'. As such, it might be handy to show what you've done and outline what the issues you have are. –  Joseph Wright Oct 29 '12 at 22:02
1  
@JosephWright Should this question be CW? There couldn't be a "correct" answer, and possibly not even a "best". –  doncherry Oct 29 '12 at 22:33
    
@JosephWright I've added my code as you asked. –  Jean Baldraque Oct 30 '12 at 18:02
    
@doncherry What is CW for? –  Jean Baldraque Oct 30 '12 at 20:22
    
add comment

3 Answers

I don't see why limiting yourself to three levels, when you can easily have as many as you wish. ;-) Just use grouping!

Notice that I took the definition of \item out of \beginenumerate, calling it \enumerateitem; then \beginenumerate does \let\item\enumerateitem, so we don't clobber Plain's \item.

All the checks you did with the level counters are gone: grouping ensures that the values are restored.

\input plipsum

\catcode`@=11
\newcount\c@listlevel
\newcount\c@item
\newdimen\enumerateindent

\def\init@str{} % the label of every item
\def\beginenumerate{%
  \begingroup
  \let\item\enumerate@item
  \advance\c@listlevel\@ne
  \ifnum\c@listlevel=\@ne
    \vskip.5\baselineskip
  \fi
  \ifnum\c@listlevel>\@ne
    \edef\init@str{\init@str\number\c@item.}%
  \fi
  \c@item\z@
}% end of \beginenumerate

\def\endenumerate{%
  \par\endgroup
  \ifnum\c@listlevel=\z@
    \vskip.5\baselineskip
  \fi}

\def\enumerate@item{%
  \advance\c@item\@ne
  \enumerateindent=\c@listlevel\parindent
  \ifvmode\else\par\fi
  % if an \item has more than one paragraph only the first one have to be preceded by a label;
  % so \@itemlabel redefine itself the first time is expanded.
  \def\@itemlabel{%
    \llap{\init@str\number\c@item.\quad}%
    \def\@itemlabel{}%
  }%
  \everypar{\setbox0\lastbox
    \hangindent\enumerateindent \hangafter\z@
    \@itemlabel}}

\catcode`@=12

\lipsum 1
\beginenumerate
  \item gjkjhg
  \item jhlujh sch
  \beginenumerate
    \item fhwoiuh
    \item eryqwo uhf u
    \item sdiuahx iuhd
    \beginenumerate
      \item xph  p \par ajioewjoo
      \item erofhx efh
      \beginenumerate
        \item xph  p \par ajioewjoo
        \item erofhx efh
        \beginenumerate
          \item \lipsum 1,2
          \item erofhx efh
          \beginenumerate
            \item xph  p \par ajioewjoo
            \item erofhx efh
          \endenumerate
        \endenumerate
      \endenumerate
    \endenumerate
  \endenumerate
  \item owhd xpqwo
\endenumerate

\bye

enter image description here

share|improve this answer
    
THIS is what I call 'elegance and functionality'. Many thanks. –  Jean Baldraque Oct 30 '12 at 19:28
    
@egreg Thanks for creating and sharing this solution. Is it possible to extend the solution to support giving symbolic names to the item number -- meaning, can one write something like "\item{aname} sdiuahx iuhd" so that latter text can refer to 2.3 using the symbol \aname? I suspect what is needed is something like "\edef\aname{\init@str}" somewhere -- but am not clear about how to make this work. –  user1823664 Jul 20 '13 at 2:00
    
@user1823664 This requires writing to an auxiliary file, just like LaTeX does. –  egreg Jul 20 '13 at 7:02
add comment

Here's one example:

\newcount\licount
\def\li#{\advance\licount by 1 \bgroup\aftergroup\par
  \noindent\llap{\the\licount.\enspace}\ignorespaces\let\next= }
\def\listend{\smallskip\noindent\ignorespaces}
\def\nlist#{\bgroup\licount=0\par\nobreak
  \advance\leftskip by\parindent \aftergroup\listend\let\next= }

\nlist{
  \li{foo}
  \li{bar}
  \nlist{
    \li{baz}
    \li{zab}
    \nlist{
      \li{rab}}}
  \li{oof}}
\bye

enter image description here

I rather like plain's \item and \itemitem because they encourage you not to make more than two levels of list items.

share|improve this answer
add comment

The eplain macro package provides a numberedlist environment for numbered lists.

\input eplain

\numberedlist
\li First item
\li Second item
\endnumberedlist

\bye
share|improve this answer
add comment

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.