编辑:已发现问题,MWE 在这里:
% !TeX program = LuaLaTeX
% !TeX encoding = UTF-8
\documentclass{article}
\usepackage{fontspec}
\setmainfont{Linux Libertine O}
\ExplSyntaxOn
\let\myaddfontfeatures\addfontfeatures
\let\addfontfeatures\relax
%% This works, with l3 2017/02/10 and fontspec-luatex 2017/02/12,
%% and prior versions:
\DeclareDocumentCommand \AddFontFeatures { m } {%%%%%%
\myaddfontfeatures{#1}%
}
\let\addfontfeatures\AddFontFeatures
%% This fails, with l3 2017/02/10 and fontspec 2017/02/12:
%% However, it works with l3 2017/02/07 and fontspec-luatex 2017/01/24.
% \DeclareDocumentCommand \addfontfeatures { m } {%%%%%%
% \myaddfontfeatures{#1}%
% }
%%
\ExplSyntaxOff
\begin{document}
Whatever.\par
{\addfontfeatures{Letters=SmallCaps} Whatever.}\par
Whatever.\par
\end{document}
在我最初的问题中,我想知道 2017/02/10 更新 l3 中是否存在错误。第二个猜测是 fontspec,2017/02/12。我有在这些更新之前运行良好的代码,但在编译时挂起失败(没有错误消息)。
从下面早期的评论中可以看出,我被引导去寻找可能的扩展问题。但事实证明,扩展与此无关。问题出在上面的代码中。
最初(上面注释掉的)我重新定义了一个文档命令,没有经过中间步骤。在更新之前,该代码运行良好。如果这是我的错误代码,它仍然运行正常。但更新导致它挂起,可能是由于自引用问题。
固定代码采用中间定义,没有问题。
快速浏览 xparser 和 fontspec-luatex 没有发现为什么会发生改变,但我不是这方面的专家。
答案1
这基本上与导致创建该letltxmacro
计划的情况相同。
和
\let\myaddfontfeatures\addfontfeatures
您定义的\myaddfontfeatures
宏与“用户级”宏相同\addfontfeatures
。直到上次更新之前xparse
,仅接受强制参数的宏使用了简化的定义,因此如果您这样做
\show\addfontfeatures
你可能会收到如下信息
\addfontfeatures=\protected macro:
#1->\fontspec_if_fontspec_font:TF [...]
从上次更新开始,精简功能不再使用,您将获得
> \addfontfeatures=\protected macro:
->\__xparse_start:nNNnnn {m}\addfontfeatures \addfontfeatures code {\__xparse_grab_m_1:w }{}{}.
它告诉我们“真实代码”被保留了下来\addfontfeatures code
(是的,宏名中有一个空格)。
现在\myaddfontfeatures
被设置为这个意思。如果你这样做
\DeclareDocumentCommand\addfontfeatures{m}{...}
一旦使用 ,就会创建一个无限循环\addfontfeatures
。实际上,这将执行\addfontfeatures code
包含对 的调用\myaddfontfeatures
,而这又将调用\addfontfeatures code
…
无限循环。
的当前定义\addfontfeatures
可以在 中找到fontspec-luatex.sty
(或者-xetex
,它们是相同的):
\DeclareDocumentCommand \addfontfeatures {m}
{
\fontspec_if_fontspec_font:TF
{
\group_begin:
\keys_set_known:nnN {fontspec-addfeatures} {#1} \l__fontspec_tmp_tl
\prop_get:cnN {g__fontspec_ \f@family _prop} {options} \l__fontspec_options_tl
\prop_get:cnN {g__fontspec_ \f@family _prop} {fontname} \l__fontspec_fontname_tl
\bool_set_true:N \l__fontspec_disable_defaults_bool
\use:x
{
\__fontspec_select_font_family:nn
{ \l__fontspec_options_tl , #1 } {\l__fontspec_fontname_tl}
}
\group_end:
\fontfamily\l_fontspec_family_tl\selectfont
}
{
\__fontspec_warning:nx {addfontfeatures-ignored} {#1}
}
\ignorespaces
}
\cs_set_eq:NN \addfontfeature \addfontfeatures
如果遵循以下指导原则会更好:
\DeclareDocumentCommand \addfontfeatures {m}
{
\fontspec_addfontfeatures:n { #1 }
}
\cs_set_eq:NN \addfontfeature \addfontfeatures
\cs_new_protected:Nn \fontspec_addfontfeatures:n
{
\fontspec_if_fontspec_font:TF
{
\group_begin:
\keys_set_known:nnN {fontspec-addfeatures} {#1} \l__fontspec_tmp_tl
\prop_get:cnN {g__fontspec_ \f@family _prop} {options} \l__fontspec_options_tl
\prop_get:cnN {g__fontspec_ \f@family _prop} {fontname} \l__fontspec_fontname_tl
\bool_set_true:N \l__fontspec_disable_defaults_bool
\use:x
{
\__fontspec_select_font_family:nn
{ \l__fontspec_options_tl , #1 } {\l__fontspec_fontname_tl}
}
\group_end:
\fontfamily\l_fontspec_family_tl\selectfont
}
{
\__fontspec_warning:nx {addfontfeatures-ignored} {#1}
}
\ignorespaces
}
所以你可以
\ExplSyntaxOn
\RenewDocumentCommand{\addfontfeatures}{m}
{
<code before>
\fontspec_addfontfeatures:n { #1 }
<code after>
}
\cs_set_eq:NN \addfontfeature \addfontfeatures
\ExplSyntaxOff
无需多个\let
步骤。
唉,它不符合指南。;-(
如果您想要禁用\addfontfeatures{Color=<color>}
,最好的策略是禁用该Color
键:
\documentclass{article}
\usepackage{fontspec}
\setmainfont{Latin Modern Roman}
\ExplSyntaxOn
\keys_define:nn { fontspec }
{
Color .code:n = ,
Colour .code:n = ,
}
\ExplSyntaxOff
\begin{document}
Abc {\addfontfeatures{Color=red} Abc}
\end{document}
您可以添加警告:
\documentclass{article}
\usepackage{fontspec}
\setmainfont{Latin Modern Roman}
\ExplSyntaxOn
\msg_new:nnn { RobtA } { invalid-key }
{
Specifying~'Color=#1'~is~disabled
}
\keys_define:nn { fontspec }
{
Color .code:n = \msg_warning:nnn { RobtA } { invalid-key } { #1 },
Colour .code:n = \msg_warning:nnn { RobtA } { invalid-key } { #1 },
}
\ExplSyntaxOff
\begin{document}
Abc {\addfontfeatures{Color=red} Abc}
\end{document}
答案2
既然 egreg 询问了,我就来解释一下我为什么使用这段代码。下面是另一个 MWE,它准确地说明了我的策略:
% !TeX program = LuaLaTeX
% !TeX encoding = UTF-8
\documentclass{article}
\usepackage{fontspec}
\usepackage[gray]{xcolor}
\usepackage{xstring}
\setmainfont{Linux Libertine O}
\def\mycheckfeature#1{}
%% Uncomment to see the difference:
% \def\mycheckfeature#1{%
% \IfSubStr{#1}{Color}{%
% \ClassError{mine}{You cannot add Color as font feature}%
% {Remove the Color font feature from your text.}%
% }{}%
% \IfSubStr{#1}{Colour}{%
% \ClassError{mine}{You cannot add Color as font feature}%
% {Remove the Color font feature from your text.}%
% }{}%
% }
%%
\ExplSyntaxOn
\let\myaddfontfeatures\addfontfeatures
\let\addfontfeatures\relax
\let\addfontfeature\relax
\DeclareDocumentCommand \AddFontFeatures { m } {%
\mycheckfeature{#1}%
\myaddfontfeatures{#1}%
}
\let\addfontfeatures\AddFontFeatures
\let\addfontfeature\AddFontFeatures
\ExplSyntaxOff
\begin{document}
It was a dark and story night. Lord Withens mounted his \textcolor{brown}{brown horse} and rode through the gloom to the {\addfontfeatures{Color=009900}Green Castle}.\par
\end{document}
必需[gray]{xcolor}
可防止棕色马出现在棕色文本中;它以灰度显示。但它不会阻止绿色城堡显示为绿色,因为 fontspec 使用不受 xcolor 控制的不同策略。
取消注释代码,看看绿色城堡中如何出现错误消息。
我也将它与 Opacity 一起使用。而且,我还拦截了\setmainfont
类似的命令。它有效。还有一些地方,我会拦截禁止的用户设置,并提供我自己的消息和说明。