这BioMed Central LaTeX 课程,,以某种方式bmcart.cls
重新定义\end
,当与 结合使用时会导致下游错误breqn.sty
。
违规内容bmcart.cls
如下:
\def\end#1{%
\@ifundefined{pseudo@#1}%
{\org@end{#1}}{\csname pseudo@#1\endcsname[1]\relax}%
}
该类别使用修改后的定义\end
来允许新语法元素的功能,\newpseudoenvironment
该语法元素似乎被发布者用来以更方便的方式定义全局定义。
很遗憾,breqn
还\end
以不兼容的方式重新定义了。在类breqn
之后加载时bmcart
,会出现以下错误:
Runaway argument?
\@ifundefined {pseudo@##1}{\org@end {##1}}{\csname pseudo@##1\endcsname \ETC.
/usr/share/texlive/texmf-dist/tex/latex/breqn/breqn.sty:848: Paragraph ended be
fore \@tempa was complete.
<to be read again>
\par
l.848 \par
bmcart.cls
如果注释掉上述几行,则不会出现该错误。
在 LianTze Lim 和 Graham Douglas 的帮助下,我现在存储了 LaTeX 默认定义,\end
然后在加载后恢复它bmcart.cls
,同时存储它的定义。此当前补丁是作为此问题的答案提供的。
虽然此解决方案允许我的项目进行编译,但它并不能完全解决根本问题,因为它不允许\newpseudoenvironment
按照预期运行(请参阅 的第 302-320 行以了解其定义及其相关的和bmcart.cls
的重新定义)(发布者可能需要)。更一般地说,找到一个允许使用 的定义的解决方案会很好,同时允许所有其他包使用适用的默认或特定于类的定义。\start
\end
breqn
\end
下面我们提供了各种命令的定义\end
,由 Graham Douglas 友情编辑:
\latexend:
\csname end#1\endcsname \@checkend {#1}\expandafter \endgroup
\if@endpe \@doendpe \fi \if@ignore \@ignorefalse \ignorespaces \fi
\brqend:
\csname end#1\endcsname \latex@end {#1}
\latex@end:
\@checkend {#1}\expandafter \endgroup \if@endpe \@doendpe
\fi \if@ignore \@ignorefalse \ignorespaces \fi
\org@end:
\csname end#1\endcsname \@checkend {#1}\expandafter \endgroup
\if@endpe \@doendpe \fi \if@ignore \@ignorefalse \ignorespaces \fi
\bmcend:
\@ifundefined {pseudo@#1}{\org@end {#1}}{\csname pseudo@#1\endcsname
[1]\relax }
有人能提出一个改进的解决方案,实现以下其中一件事(或提出一些更好的替代方案)吗?
- 封装这样
breqn
的定义\end
,使得它不会引起兼容性问题,但仍可用于所有breqn
环境。 - 封装
bmcart.cls
的定义\end
,使得它不会引起兼容性问题,但允许pseudo@#1
自动定义其相关情况并仅由 使用\newpseudoenvironment
。 - 加载后恢复
bmcart.cls
的定义,但仍允许环境(如)正常运行。\end
breqn.sty
breqn
dmath
答案1
诀窍在于,两个包都可以正常工作,如果breqn
\end
在里面使用bmcart
\end
,则breqn
必须先加载。这会很奇怪,并可能导致其他错误,因此我们交换了定义:
\documentclass{bmcart}
\makeatletter
\let\bmcend\end % save \bmcend
\let\end\org@end % breqn has to see the original \end
\usepackage{breqn}
\let\org@end\end % let bmcart believe the breqn \end is the original
\let\end\bmcend % and give control back to bmcart
\makeatother
% Some demonstration
\newpseudoenvironment{pseudo}{}{}
\newenvironment{real}{}{}
\begin{document}
\begin{dmath}
abc=def=ghi=jkl
\end{dmath}
\begin{real}
\the\currentgrouplevel
\end{real}
\begin{pseudo}
\the\currentgrouplevel
\end{pseudo}
\end{document}
我添加了一些环境来显示一切正常。特别是没有由伪环境创建的组:
您无需在加载包之前和之后使用命令拆分此修复,而是可以使用包scrlfile
将命令插入到正确的位置:
\documentclass{bmcart}
\usepackage{scrlfile}
\makeatletter
\BeforePackage{breqn}{
\let\bmcend\end % save \bmcend
\let\end\org@end % breqn has to see the original \end
}
\AfterPackage{breqn}{
\let\org@end\end % let bmcart believe the breqn \end is the original
\let\end\bmcend % and give control back to bmcart
}
\makeatletter
\usepackage{breqn}
如果它由另一个包加载,这尤其有用breqn
,即使根本没有加载它也能工作。
或者,bmcart
伪环境可以集成到系统中breqn
:伪环境只需要定义一个\end...
包含两个参数的命令:
\documentclass{bmcart}
\makeatletter
\let\end\org@end
\def\newpseudoenvironment#1#2#3{%
\global\@namedef{end#1}##1##2{#3}%
\global\@namedef{pseudo@#1}[##1]{%
\relax#2%
}%
}
\makeatletter
\usepackage{breqn}
我认为第二种方法看起来更简洁,但在某些特殊情况下可能会失效:
伪环境与正常环境有两个根本区别:
它不引入组。这意味着伪环境内的定义可能会泄漏到环境中。例如,假设
pseudo
和real
是上面代码片段中的伪环境,那么\begin{real} \scshape This is in small caps. \end{real} Here we have a normal font again. \begin{pseudo} \scshape This is in small caps again \end{pseudo} Oops, still small caps.
例如,这对于类似于 LaTeX
lrbox
环境的环境很有用。它将其内容保存在作为参数传递的保存框中。为了使保存框的分配在环境之外可见,必须避免分组。这可以通过伪环境来实现。lrbox
本身必须使用一些技巧。这可能是伪环境的预期用例。
还有另一个区别。如果你曾经尝试创建一个名为 eg 的环境
def
(例如用于定义),你就会知道不可能存在与 LaTeX 宏同名的 LaTeX 环境,因为名为 eg 的环境foo
是由宏\foo
和定义的\endfoo
。这种命名冲突已在伪环境中得到解决,因此\newpseudoenvironment{def}{Definition: }{. End of Definition} % or even \newcommand\something{I'm a macro.} \newpseudoenvironment{something}{I'm an environment.}{The end.}
是有效的。如果必须将相同的功能作为命令和环境提供,这将很有用。使用一些技巧与正常环境产生类似效果的一个例子是
beamer
s\frame
和{frame}
。这也适用于
\end...
。因此你可以定义\newcommand\endsomething{...} \newpseudoenvironment{something}{...}{...}
这种情况下,一个独立的
\end...
宏可以与bmcart
第一个修复一起使用,但不能与第二个修复一起使用。但我不知道为什么有人会这样做,所以这通常不应该是个问题。另外,LaTeX 不允许定义任何以\end...
via开头的命令\newcommand
,所以这需要使用\def
原语。
对于第一种方法来说这应该不是问题。
答案2
注意:这个答案不能从总体上令人满意地解决上述问题。如果能提供更多想法,我将不胜感激。
上面提到的当前补丁如下:
% before loading bmcart.cls
\RequirePackage{letltxmacro}
\GlobalLetLtxMacro{\LaTeXend}{\end}
% ...
% after loading the class
\LetLtxMacro{\bmcend}{\end}
\LetLtxMacro{\end}{\LaTeXend}
% ...
\usepackage{breqn}