自身包选项中存在“未定义的控制序列”,但不在文档中

自身包选项中存在“未定义的控制序列”,但不在文档中

这是我的第一个问题,如果有任何错误请见谅!

我正在尝试使用 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-optexpkv-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

相关内容