在列表中使用 \expandafter\csname 等时,代码因紧急停止而失败

在列表中使用 \expandafter\csname 等时,代码因紧急停止而失败

我正在进一步编写 LaTeX 示例代码。我想使用 showexpl 包同时打印代码和结果。不幸的是,我得到了“!紧急停止。”

\documentclass{scrbook}
\makeatletter
\providecommand{\packagename}{templatedemo}
\RequirePackage{etoolbox}
\RequirePackage{showexpl}

\providecommand\AddDemo[3][]{%
  \expandafter\providecommand\csname demo@content@#2\endcsname{#3}%
  \expandafter\providecommand\csname demo@options@#2\endcsname{#1}%
}

\providecommand\demo@printhis{}
\providecommand\PrintDemo[1]{%
  \ifcsdef{demo@content@#1}%
  { % print 
    \renewcommand{\demo@printhis}{\expandafter\csname demo@content@#1\endcsname}
    \begin{LTXexample} 
      \demo@printhis
    \end{LTXexample} 
  }%
  {}
}

\AddDemo{text}{Sample Text}% end: \AddDemo

\makeatother
\listfiles

\begin{document}
  \PrintDemo{text}
\end{document}

如果这个方法可行,那么下一个问题就是列表将只显示扩展版本。因此,如果我这样写:

\begin{document}
    \begin{LTXexample} 
      \PrintDemo{text}
    \end{LTXexample} 
\end{document}

列表包将输出“\PrintDemo{text}”而不是其内容。

答案1

您的代码中存在许多问题。主要问题是,它LTXexample是一种非常类似的环境verbatim,无法在命令的参数中使用。

在某些情况下,可以通过 来规避这个问题\scantokens。但是,你继续的方法不会考虑输入中的换行符;至少在不对类别代码进行大修的情况下不会,因为代码会被读取多次,所以无论如何都会中断;一旦字符标记进入 TeX,其类别代码就会固定。\scantokens可以重新读取它并重新分配类别代码,但一旦将其传递给LTXexample该问题就会再次出现。

为了展示一种可能性,这里有一个尝试:

\newcommand\AddDemo[3][]{%
  \expandafter\newcommand\csname demo@content@#2\endcsname{#3}%
  \expandafter\newcommand\csname demo@options@#2\endcsname{#1}%
}

\newcommand\PrintDemo[1]{%
  \ifcsdef{demo@content@#1}%
  { % print 
    \letcs\next{demo@content@#1}%
    \toks@=\expandafter{\next}%
    \edef\next{\unexpanded{\begin{LTXexample}}^^J%
      \the\toks@^^J%
      \unexpanded{\end{LTXexample}}}%
    \scantokens{\next}%
  }%
  {}
}

\makeatother

\AddDemo{text}{Sample Text}% end: \AddDemo

你可以尝试一下,看看它是否按预期工作。但是

\AddDemo{text}{Sample
   Text}

将以完全相同的方式打印(这在代码示例中通常不是故意的)。然而,主要问题是

\AddDemo{text}{Sample Text \today}

将会打破列表(由 所使用LTXexample)。尝试一下。

一些评论

您对 的使用\providecommand是错误的;\providecommand\AddDemo如果 已经定义,它将被默默忽略\AddDemo。假设某个包定义了它:您将对结果感到非常困惑。

在 的定义中也是错误的\AddDemo;说

\AddDemo{text}{demo1}
...
\AddDemo{text}{demo2}

被错误地使用:\PrintDemo{text}总是会使用demo1,并且您不会收到有关双重定义的通知。

也是\expandafter\csname demo@content@#1\endcsname值得怀疑的:\expandafter会试图扩张d(当然是不可扩张的);其效果与 完全相同\csname demo@content@#1\endcsname。在其他情况下,放错\expandafter可能会造成灾难。

我可以理解您希望将所有代码示例放在一个地方,但是排版 TeX 代码需要微妙之处,这使得这个目标很难(如果不是不可能)实现。

相关内容