这是我的第一个问题,如果有任何错误请见谅!
我正在尝试使用 clsguide 创建一个包。在包中,我定义了一个自己的命令,我想用它来设置一个选项(将命令的内容存储在一个变量中)。
该包的一个示例:
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{example}
\DeclareKeys{
owncommand.code = \newcommand{\owncmd}{Use this text.}
}
\DeclareKeys{
expression.store = \@expression
expression.usage = load
}
\ProcessKeyOptions
\endinput
文档示例:
\documentclass[11pt]{scrartcl}
\usepackage[owncommand, expression = \owncmd]{example}
\begin{document}
Test.
\end{document}
但我收到了错误:
! Undefined control sequence.
<argument> \owncmd
在文档中使用 \owncmd 不会出错。所以实际上 \owncmd 并非未定义。我哪里犯了错误?
编辑:因为我被要求提供用例。这是一个供个人使用的包。我想创建带有当前学习单元的工作表,如下所示:
我经常需要使用这种“特殊”符号。这就是为什么我只需定义一个命令即可获得正确的符号。因此我修改了包:
\begin{filecontents}[overwrite]{\jobname.sty}
\NeedsTeXFormat{LaTeX2e}
\RequirePackage{fontspec}
\RequirePackage{babel}
\RequirePackage{scrlayer-scrpage}
\DeclareKeys[serdar]{
fancysymbol.code = {
\newfontfamily\arabicfont{Microsoft Uighur}
\newcommand{\fancysymb}{
\foreignlanguage{arabic}{\LARGE\arabicfont ﷺ}
}
},
worksheettopic.store = \@worksheettopic,
worksheetlayout.code = {\chead{\@worksheettopic}}
}
\ProcessKeyOptions[serdar]
\endinput
\end{filecontents}
\documentclass[11pt]{scrartcl}
\usepackage[
fancysymbol,
worksheettopic = {The Prophet \fancysymb},
worksheetlayout
]{\jobname}
\begin{document}
Test.
\end{document}
如果我正确理解了您的解决方案,它们只适用于选项worksheettopic = fancysymb
,而不适用于“组合”选项worksheettopic = The Prophet fancysymb
。
当然,在加载包后,可以\chead
在序言中移动。但我在包内寻找解决方案。有没有(简单的)可能性?
答案1
问题是现代 LaTeX 有两种并行的包选项机制。第一种使用 -expression 中的整个选项列表\edef
,因此您的输入必须对 是安全的\edef
(因此如果您输入\owncmd
,则会失败,因为在您提交选项时它没有定义),另一种机制将密钥“按原样”转发到底层包。因此,您的选项必须受到保护以防止扩展,但同时,如果您的 key=value 解决方案使用新的“按原样”方法,您的保护机制不得干扰未扩展形式的列表。
内置\ProcessKeyOptions
使用“原样”列表。因此,您不能只使用\protect
不扩展您的\owncmd
,而不会\protect
在键的结果中显示它。出于这个原因,下面建议使用expkv-opt
。expkv-opt
也使用“原样”列表,但在使用时支持扩展表达式。这样就可以保护您的,\owncmd
而使用的保护机制实际上不会显示在值中。
\begin{filecontents}[overwrite]{\jobname.sty}
\NeedsTeXFormat{LaTeX2e}
\RequirePackage{expkv-def,expkv-opt}
\ekvdefinekeys{serdar}
{
protected code owncommand = \newcommand\owncmd{Use this text.}
,store expression = \serdarexpression
}
\ekvoProcessLocalOptions{serdar}
\endinput
\end{filecontents}
\documentclass[11pt]{scrartcl}
% any of the following lines work
% using the result of \csname owncmd\endcsname as value for expression
\usepackage[owncommand, c: expression = owncmd]{\jobname}
% expanding \unexpanded{\owncmd} once (resulting in \owncmd)
%\usepackage[owncommand, o: expression = \unexpanded{\owncmd}]{\jobname}
% gobbling \protect leaving just \owncmd
%\usepackage[owncommand, g: expression = \protect\owncmd]{\jobname}
\begin{document}
Test.
\serdarexpression
\end{document}
具有您的扩展 MWE 的变体(没有排版结果,我没有字体,而且我不想花时间搜索包含您的字形的字体):
\begin{filecontents}[overwrite]{\jobname.sty}
\NeedsTeXFormat{LaTeX2e}
\RequirePackage{fontspec}
\RequirePackage{babel}
\RequirePackage{scrlayer-scrpage}
\RequirePackage{expkv-def, expkv-opt}
\ekvdefinekeys{serdar}
{
protected noval fancysymbol =
\newfontfamily\arabicfont{Microsoft Uighur}%
\newcommand{\fancysymb}{\foreignlanguage{arabic}{\LARGE\arabicfont ﷺ}}
,store worksheettopic = \@worksheettopic
,protected noval worksheetlayout = \chead{\@worksheettopic}
}
\ekvoProcessLocalOptions{serdar}
\endinput
\end{filecontents}
\documentclass[11pt]{scrartcl}
\usepackage[
fancysymbol,
o: worksheettopic = \unexpanded{The Prophet \fancysymb},
worksheetlayout
]{\jobname}
\begin{document}
Test.
\end{document}
您的问题有一个非常简单的解决方案:不要使用包选项进行这些设置,而是以提供“setup”宏的方式设置您的包,该宏在包加载后执行选项处理。例如:
\begin{filecontents}[overwrite]{\jobname.sty}
\NeedsTeXFormat{LaTeX2e}
\RequirePackage{fontspec}
\RequirePackage{babel}
\RequirePackage{scrlayer-scrpage}
\RequirePackage{expkv-def, expkv-opt}
\ekvsetdef\serdarsetup{serdar}
\ekvdefinekeys{serdar}
{
protected noval fancysymbol =
\newfontfamily\arabicfont{Microsoft Uighur}%
\newcommand{\fancysymb}{\foreignlanguage{arabic}{\LARGE\arabicfont ﷺ}}
,store worksheettopic = \@worksheettopic
,protected noval worksheetlayout = \chead{\@worksheettopic}
}
\endinput
\end{filecontents}
\documentclass[11pt]{scrartcl}
\usepackage{\jobname}
\serdarsetup{
fancysymbol,
worksheettopic = The Prophet \fancysymb,
worksheetlayout
}
\begin{document}
Test.
\end{document}
这完全避免了处理选项列表的问题。
答案2
很难猜测您为什么要这样做,但您可以传递一个不带反斜杠的命令,这样expression
您就可以在处理选项后使用该命令本身。
\begin{filecontents}[overwrite]{\jobname.sty}
\NeedsTeXFormat{LaTeX2e}
\DeclareKeys[serdar]
{
owncommand.code = {\newcommand{\owncmd}{Use this text.}},
expression.store = \@expression,
expression.usage = load,
}
\ProcessKeyOptions[serdar]
\newcommand\serdarexpression{\csname \@expression\endcsname}
\endinput
\end{filecontents}
\documentclass[11pt]{scrartcl}
\usepackage[owncommand, expression = owncmd]{\jobname}
\begin{document}
Test.
\serdarexpression
\end{document}
答案3
如果您想要这个,您可以或多或少使用任何强大的预先存在的命令(因此它被定义)并在本地用该命令替换已保存的定义,因此\star
在这里使用。
\documentclass[11pt]{scrartcl}
\usepackage[owncommand, expression = something using: \star]{example}
\begin{document}
Test.
Expression: \makeatletter \@expression\makeatother
star is still $\star$
\end{document}
您会看到,除了本地的 keyval 之外,它\star
仍然是其他选项指定的命令的占位符。(这个占位符可能是一个标记,也许比更清楚)*
*
\star
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{example}
\DeclareKeys{
owncommand.code = \def\starreplace{Use this text.}
}
\DeclareKeys{
expression.store = \@expression,
expression.usage = load
}
\ProcessKeyOptions
\ExplSyntaxOn
\tl_replace_all:Nnn\@expression\star\starreplace
\ExplSyntaxOff
\endinput