例如,在 之后\paragraph{1}
,所有换行符都将被忽略,下一个文本将从段落名称旁边开始。我想在命令中添加一些也会忽略下一个换行符的内容,这样我可以在命令后留下一个空行,但 latex 仍会继续在命令输出旁边写入。更详细地说,我想要
\cmd{Hi}
Bye
屈服
Hi Bye
但现在它给了我
Hi
Bye
如果我cmd
用替换paragraph
,就会实现所需的输出,因此必须有一种方法可以做到这一点。
答案1
解决方案灵感来自\@xsect
\documentclass{article}
\makeatletter
\newcommand*{\my@pseudo@xsect}[1]{%
\@nobreakfalse
\global\@noskipsectrue
\everypar{%
\if@noskipsec
\global\@noskipsecfalse
{\setbox\z@\lastbox}% remove paragraph indentation
\my@stored@stuff
\hspace{#1}% you could remove this, use a control space, etc.
\else
\everypar{}% restore \everypar
\fi}%
\ignorespaces
}
\newcommand*{\my@stored@stuff}{} % make sure the name isn't already taken
% The optional argument is the amount of horizontal glue inserted after the
% “first part.” It is passed to the \hspace command in \my@pseudo@xsect, which
% could be removed if no space is wanted, replaced by a control space,
% whatever.
\newcommand*{\mycmd}[2][1em]{%
\if@noskipsec\leavevmode\fi \par
\renewcommand*{\my@stored@stuff}{\emph{#2}}% for instance
\my@pseudo@xsect{#1}%
}
\makeatother
\begin{document}
\bigskip
\mycmd{Hi!}
Bye.
\bigskip
\mycmd[0pt]{With zero-width glue:}
I am very close to the colon!
\bigskip
\mycmd{A list environment follows:}
\begin{itemize}
\item foo
\item bar
\end{itemize}
\bigskip
\mycmd[0.7em]{This also works:} because of the \verb|\par| in \verb|\mycmd|.
\end{document}
如果您想了解其工作原理,请阅读下一部分。
直接使用\@xsect
以下是答案的第一个版本。由于重用了 ,因此代码比我上面发布的代码短\@xsect
。不过,它几乎没有可能对您不利的副作用(最值得注意的是将 设置为\clubpenalty
10000)。如果您希望命令表现得像伪 ,请使用它\paragraph
。
因此,当给定一个非正跳过作为参数时,我们可以重复使用\paragraph
所依赖的机制:\@xsect
不会阻止在包含运行部分标题的行之前分页(请参阅
\@nobreakfalse
本答案末尾的代码),并且;重新定义
\everypar
,以便当下一段开始时,执行以下操作:删除缩进框(
\setbox\z@\lastbox
);段落第一行后不允许分页(
\clubpenalty
设置为10000);宏
\@svsechd
被展开并且其代码在一个组内执行(这通常会排版运行的“部分”编号和标题,其中“部分”代表\paragraph
或\subparagraph
);如果这个左粘连是当前列表的最后一项(希望是水平的),则使用 将其删除
\unskip
;\@xsect
插入一个与 参数相反的水平跳跃;修改后所做的所有这些事情
\everypar
都是一次性的:当下一段开始时,的标准值\clubpenalty
将恢复(LaTeX 先前将其保存在中\@clubpenalty
)并\everypar
重置为空标记列表(即,它不会对后续段落执行任何操作)。
因此,如果您的命令重新定义\@svsechd
为按您想要的方式排版“Hi”,然后\@xsect
以负跳过作为参数调用,则该机制将打印“Hi”,使用与跳过参数相反的参数插入水平粘连\@xsect
,扩展后面的内容,忽略空格标记(因为\@xsect
以结尾\ignorespaces
),最后,您将获得触发段落开头的“Bye”,从而导致修改\everypar
排版“Hi”。 (深呼吸。)你明白了吗? :-)
\documentclass{article}
\makeatletter
\newcommand*{\mycmd}[1]{%
\if@noskipsec\leavevmode\fi \par
\def\@svsechd{\emph{#1}}%
% Horizontal glue inserted will be 1em. With 0em, “Hi!” and “Bye” would be
% stuck to each other.
\@xsect{-1em}%
}
\makeatother
\begin{document}
\mycmd{Hi!}
Bye.
\end{document}
如果您不想产生诸如\clubpenalty
设置为 10000 之类的小副作用,您可以将 的有趣部分复制\@xsect
到您的宏中,例如不带\clubpenalty\@M
,并使用修改后的宏代替\@xsect
(这正是我们在第一个示例中所做的)。最后,这归结为存储需要存储的任何内容,为其分配一个新值\everypar
,当下一个段落开始时,首先使用已存储的内容产生内容,然后安排事情,以便下一个段落开始时,事情将恢复正常。
当然还有其他方法可以做这样的事情,比如临时重新定义\par
或编写吞噬标记的宏\par
。
\@xsect
作为参考,我上面描述的部分是:
\def\@xsect#1{%
\@tempskipa #1\relax
\ifdim \@tempskipa>\z@
... % irrelevant to this discussion (non-run-in headings)
\else % this is the case concerning run-in headings
\@nobreakfalse
\global\@noskipsectrue
\everypar{%
\if@noskipsec
\global\@noskipsecfalse
{\setbox\z@\lastbox}%
\clubpenalty\@M
\begingroup \@svsechd \endgroup
\unskip
\@tempskipa #1\relax
\hskip -\@tempskipa
\else
\clubpenalty \@clubpenalty
\everypar{}%
\fi}%
\fi
\ignorespaces}