纯 TeX 中的列表宏示例

纯 TeX 中的列表宏示例

我正在编写宏来用纯 TeX 排版列表。您能否推荐一些编号列表宏的示例?我更喜欢“活代码”中的示例、CTAN 包中的示例等等。但任何形式的帮助都会很感激。

我编写了可行的代码,但有点麻烦,所以我正在寻找优雅和功能性的示例。


[编辑] Joseph Wright 说,展示我所做的工作并概述我遇到的问题可能会很方便。好吧,我没有遇到什么真正的问题,但担心代码的可扩展性和可维护性。正如我所说,代码可以工作,但它很复杂,宏太长,缺乏优雅。

嗯,目标是排版像这样的编号列表。

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

界面将会像这样

\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

因此我将使用以下变量:

\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=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}

Wright 先生,您有没有什么办法可以让代码变得更好一点?非常感谢。

答案1

我不明白为什么要将自己限制为三个级别,因为您可以轻松拥有任意数量的级别。;-)只需使用分组即可!

\item请注意,我从中取出了 的定义\beginenumerate,称之为\enumerateitem;然后\beginenumerate执行\let\item\enumerateitem,因此我们不会破坏 Plain 的\item

您使用级别计数器进行的所有检查都消失了:分组确保恢复值。

\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

在此处输入图片描述

答案2

埃普莱恩macro 包为编号列表提供了 numberedlist 环境。

\input eplain

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

\bye

答案3

以下是一个例子:

\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

在此处输入图片描述

我更喜欢 plain 的\item\itemitem因为它们鼓励你不要制作超过两层的列表项。

相关内容