DeclareDocumentEnvironment:缺少插入的控制序列 - \inaccessible

DeclareDocumentEnvironment:缺少插入的控制序列 - \inaccessible

我正在为一位朋友设置一个骨架简历包,供他自定义,我想让它尽可能方便用户使用。为此,我使用了keyvalxparse

\begin{filecontents}{setup.sty}
  \RequirePackage{xparse}
  \RequirePackage{keyval}
  \define@key{position}{title}  {\def{\position@title}  {#1}}
  \define@key{position}{date}   {\def{\position@date}   {#1}}
  \define@key{position}{company}{\def{\position@company}{#1}}
  \define@key{position}{place}  {\def{\position@place}  {#1}}
  \DeclareDocumentEnvironment{position}{m}{%
    \begingroup
    \IfNoValueTF{#1}
    {\setkeys{position}{title={},date={},company={},place={}}}
    {\setkeys{position}{title={},date={},company={},place={},#1}}

    \begin{description}
    \item[Title]   \position@title
    \item[Date]    \position@date
    \item[Company] \position@company
    \item[Place]   \position@place
    \end{description}
    \endgroup
  }{}
\end{filecontents}
\documentclass{article}
\usepackage{setup}

\begin{document}
\begin{position}{title=hello}
  Hey
\end{position}
\end{document}

在我看来,这似乎是xparseand的一个相当标准的用法keyval,所以我很可能错过了一些相当简单和 Read-The-Fine-Manual-y 的东西,但我找不到任何错误,而且错误消息对我来说仍然很神秘——我以前从未遇到过。以下是错误消息的全部内容:

ERROR: Missing control sequence inserted.

--- TeX said ---
<inserted text> 
                \inaccessible 
l.55 \begin{position}{title=hello}

--- HELP ---
This is probably caused by a \newcommand, \renewcommand, \newlength,
or \newsavebox command whose first argument is not a command name.

这里发生了什么?我怎样才能让 TeX 再次正常运行?

顺便说一句,如果有人愿意xkeyval在他们的答案中给出等效的解决方案,我总是很高兴学到一些新东西:-)。


我被 AUCTeX 宠坏了;日志文件中还有更多错误可能更有帮助:

... style imports ...
! Missing control sequence inserted.
<inserted text> 
                \inaccessible 
l.56 \begin{position}{title=hello}

! Missing control sequence inserted.
<inserted text> 
                \inaccessible 
l.56 \begin{position}{title=hello}

! Missing control sequence inserted.
<inserted text> 
                \inaccessible 
l.56 \begin{position}{title=hello}

! Missing control sequence inserted.
<inserted text> 
                \inaccessible 
l.56 \begin{position}{title=hello}

! Missing control sequence inserted.
<inserted text> 
                \inaccessible 
l.56 \begin{position}{title=hello}

! Undefined control sequence.
\environment position code ...le] \position@title 
                                                  \item [Date] \position@dat...
l.56 \begin{position}{title=hello}

! Undefined control sequence.
\environment position code ...ate] \position@date 
                                                  \item [Company] \position@...
l.56 \begin{position}{title=hello}

! Undefined control sequence.
\environment position code ...] \position@company 
                                                  \item [Place] \position@pl...
l.56 \begin{position}{title=hello}

! Undefined control sequence.
\environment position code ...ce] \position@place 
                                                  \end {description} \endgroup l.56 \begin{position}{title=hello}
... see transcript file for additional information, etc. etc. ...

答案1

\def是一个具有语法的原始命令

\def<control sequence><parameter text>{<replacement text>}

其中<control sequence>表示以 开头的控制序列名称,\或表示活动字符。 后面的任何其他标记\def都是非法的,TeX 会尝试通过插入名为 的特殊控制序列来恢复\inaccessible。 错误消息非常清楚:

! Missing control sequence inserted.
<inserted text>
                \inaccessible
<to be read again>
                   {
l.18 \def{
          \position@title}  {hi}

您可以看到 TeX 停止的位置:它{在 之后发现\def;有问题的{标记已放回输入流中,并将再次读取,就像尚未读取一样。在 和 之间,\defTeX{插入了\inaccessible,您仍然可以通过键入 来删除它1,然后i\foo插入您可能忘记添加的控制序列名称(至少 TeX 是这么想的)。

如果你对低级 TeX 命令不太有信心,你仍然可以坚持使用 LaTeX 的模型。只需在命令\position@title前进行初始化\define@key

\newcommand{\position@title}{}
\define@key{position}{title}{\renewcommand{\position@title}{#1}}

\newcommand允许在或的第一个参数周围使用括号\renewcommand(LaTeX 手册总是使用它们)但不是必需的。

实际上,初始化容器可以避免稍后设置键时出现笨拙的代码。

让我们看看你的代码:

\DeclareDocumentEnvironment{position}{m}{%
  \begingroup
  \IfNoValueTF{#1}
  {\setkeys{position}{title={},date={},company={},place={}}}
  {\setkeys{position}{title={},date={},company={},place={},#1}}

  \begin{description}
  \item[Title]   \position@title
  \item[Date]    \position@date
  \item[Company] \position@company
  \item[Place]   \position@place
  \end{description}
  \endgroup
}{}

没有必要设置具有空值的键,因为如果您已经初始化它们,则默认值无论如何都是空的。

\IfNoValueTF另一件需要注意的事情是,意志的真正分支绝不\begingroup注意:该函数用于可选参数,而不是强制参数。和也不需要\endgroup,因为键将设置在由 打开的组中\begin{position}

因此更有效的代码是

\newcommand{\position@title}  {}
\newcommand{\position@date}   {}
\newcommand{\position@company}{}
\newcommand{\position@place}  {}
\define@key{position}{title}  {\renewcommand{\position@title}  {#1}}
\define@key{position}{date}   {\renewcommand{\position@date}   {#1}}
\define@key{position}{company}{\renewcommand{\position@company}{#1}}
\define@key{position}{place}  {\renewcommand{\position@place}  {#1}}
\DeclareDocumentEnvironment{position}{m}
  {%
   \setkeys{position}{#1}
   \begin{description}
   \item[Title]   \position@title
   \item[Date]    \position@date
   \item[Company] \position@company
   \item[Place]   \position@place
   \end{description}
  }{}

我建议采用稍微不同的方法:您可以使用l3keys

\ExplSyntaxOn
\keys_define:nn { sean/position }
 {
  title   .tl_set:N = \l_sean_position_title_tl,
  date    .tl_set:N = \l_sean_position_date_tl,
  company .tl_set:N = \l_sean_position_company_tl,
  place   .tl_set:N = \l_sean_position_place_tl,
 }
\NewDocumentEnvironment{position}{m}
 {
  \begin{description}
  \keys_set:nn { sean/position } { #1 }
  \item[Title]   \l_sean_position_title_tl
  \item[Date]    \l_sean_position_date_tl
  \item[Company] \l_sean_position_company_tl
  \item[Place]   \l_sean_position_place_tl
  \end{description}
 }{}
\ExplSyntaxOff

\keys_define:nn功能\keys_set:nn已可用\usepackage{xparse}

答案2

来自TeX 书第 20 章 定义(也称为宏),第 203 页):

...让我们看看控制 TeX 宏的精确规则。定义具有一般形式

\def<control sequence><parameter text>{<replacement text>}

其中<parameter text>不包含,并且中braces的所有{和都正确嵌套。此外,符号具有特殊意义:在 中,第一次出现的 后面必须跟 ,下一次跟 ,依此类推;最多允许九个 。在每个 中 , 后面必须跟在 之后出现的数字 ,否则 后面 应该跟另一个 。后一种情况代表宏展开时的单个 标记;前一种情况代表插入相应的参数。}<replacement text>#<parameter text>#12#<replacement text>##<parameter text>###

由此可见,<control sequence>不需要支撑。


关于您使用keyval,你也可以使用xkeyval的“命令键” \define@cmdkey。从xkeyval文档(部分3.2 命令键,第 5 页):

以下两行也用同样的键宏实现了一个键:

\define@cmdkey{fam}[my@]{key}[none]{value: \my@key}% xkeyval syntax
\define@key{fam}{key}[none]{\def\mykey{#1}value: \my@key}% keyval syntax

答案3

这实际上没有什么与 {xparse}、{keyval} 或 {environments} 完全无关。我所需要做的就是从 中删除括号\def

我正在尝试 Joseph Wright 的TUGBoat 文章keyval接口上,并决定尝试第 111 页的建议,position@title即在实际制作键之前定义容器宏(例如)。这弹出了一个不同的错误,但肯定更明确:

ERROR: Missing control sequence inserted.

--- TeX said ---
<inserted text> 
                \inaccessible 
l.18 \def{
          \position@title}  {hi}
--- HELP ---
This is probably caused by a \newcommand, \renewcommand, \newlength,
or \newsavebox command whose first argument is not a command name.

从这里可以相对明显地看出,{}字符是问题的根源,尽管我还是不知道为什么为此目的所获得的任何额外资源都将受到高度赞赏。

相关内容