解决方案灵感来自\@xsect

解决方案灵感来自\@xsect

例如,在 之后\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。不过,它几乎没有可能对您不利的副作用(最值得注意的是将 设置为\clubpenalty10000)。如果您希望命令表现得像伪 ,请使用它\paragraph

因此,当给定一个非正跳过作为参数时,我们可以重复使用\paragraph所依赖的机制:\@xsect

  1. 不会阻止在包含运行部分标题的行之前分页(请参阅\@nobreakfalse本答案末尾的代码),并且;

  2. 重新定义\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}

相关内容