Examples of list macros in plain TeX

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.

 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


\def\beginenumerate{\begingroup

\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@...
\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{%
\gdef\@itemlabel{}}%

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

\def\endenumerate{%
\ifnum\c@listlevel=\z@\else
\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.

-
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
@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

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
\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{%
\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{%
\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


-
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

Here's one example:

\newcount\licount
\noindent\llap{\the\licount.\enspace}\ignorespaces\let\next= }
\def\listend{\smallskip\noindent\ignorespaces}
\def\nlist#{\bgroup\licount=0\par\nobreak

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


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

-

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

\input eplain

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

\bye

-