我正在尝试使用宏来构建带标题行的描述列表。在非 MWE 中,宏会添加索引条目和边注等附加值,但这里我的情况是最简单的。
\documentclass{article}
\newcommand{\pni}[1]{\item{#1} The name of the rose\par\noindent}
\newcommand{\dbs}[1]{\item{#1} The name of the rose\\}
\begin{document}
\begin{description}
\dbs{abc def}
A book that isn't about roses.
Another paragraph
\pni{abc def}
A book that isn't about roses, either.
Another paragraph
\pni{abc def}%
A book that isn't about roses, either.
Another paragraph\end{description}
\end{document}
描述项的第一行由关键字和标题组成;其余部分是段落中的描述性文本。
现在,我认为从语义上讲,使用 来\par\noindent
准备文本的第一段会更好,因为这将遵循段落的“其他定义”,而不是\\
,后者只是一个换行符。但正如您所见,\par\noindent
在新段落的开头引入了一个虚假的空格。
我知道我可以通过%
在我的调用中添加来抑制这种情况,但我更愿意在宏内执行此操作。怎么做?
根据迄今为止的答案(感谢并向@DavidCarlisle和@egreg致歉),这是第二个更准确反映我的情况的MWE。我正在使用enumitem
,memoir
我现在看到它使我的原始MWE有点过于简单化。如下:
\documentclass{memoir}
\usepackage{tgpagella}
\usepackage{xparse}
\usepackage{enumitem}
\newlist{mfields}{description}{1}
\setlist[mfields]{%
font=\bfseries\scshape,leftmargin=!,labelwidth=3.5em,
labelsep=0.5em,itemindent=0pt,listparindent=\parindent}
\DeclareDocumentCommand{\mfield}{m m}{%
\item[#1]#2\par}
\DeclareDocumentCommand{\xfield}{m m}{%
\item[#1]#2\par\noindent\ignorespaces}
\begin{document}
\begin{mfields}
\mfield{abcdef}{The Name of The Rose}
A book that isn't about roses.
Another paragraph goes here etc.
\xfield{ghijkl}{The Island of the Day Before}
A book that isn't about roses, either.
Another paragraph goes here etc.
\xfield{mnopqr}{The Island of the Day Before}
A book that isn't about roses, either.
Another paragraph goes here etc.
\end{mfields}
\end{document}
答案1
TeX 换行算法的一个基本特性是,行首的粘连(包括空格的粘连)会被丢弃。但由于段落\noindent
已经开始,因此后面的空格标记会产生不会被丢弃的粘连(因为它不在换行符后面)。
看起来你The name of the rose
应该成为列表标签的一部分(可选参数\item
),而不是在它之后强制中断。
如评论中所述,\par\noindent
如果命令后面有一个空白行,则会产生生成虚假空段落的不良影响,并且 \par\noindent\ignorespaces
无法解决此问题。但是在这种情况下,无论如何您都有 0pt 缩进,因此更简单的定义是
\newcommand{\pni}[1]{\item{#1} The name of the rose\par}
空格标记和空白标记将被忽略,\par
并且段落将以 0 宽度缩进开始。
或者如果\listparindent
不是 0
\newcommand{\pni}[1]{\item{#1} The name of the rose\par\bgroup\parindent\z@\everypar{\egroup}}
答案2
无论何时,在带有参数的宏末尾使用\noindent
(或\indent
),最好添加\ignorespaces
:您看到的空格是由于 之后的行尾引起的\pni{abc def}
。
所以
\newcommand{\pni}[1]{\item{#1} The name of the rose\par\noindent\ignorespaces}
就是答案。
为什么这种情况不会发生\\
?因为这个宏有一个*
变体(和一个可选参数,它本身就足够了)和查找*
吃掉的空格。在这种情况下,它无论如何都不会产生任何影响,因为空格位于行的开头。
关于新的例子,如果您想要的是两个\xfield
项目给出相同的结果,也就是说,在第二个项目中忽略空行,您可以定义一个\ignorespacesandpars
命令来代替\ignorespaces
。
\makeatletter
\newcommand{\ignorespacesandpars}{%
\@ifnextchar\par{\@ignorespacesandpars}{}}
\long\def\@ignorespacesandpars#1{\noindent\ignorespacesandpars}
\makeatother
空格会被吃掉\@ifnextchar
,而\par
token 则会在去掉之后再次调用自身\par
。