解决 \scantokens 中打开 lualatex 错误的办法?

解决 \scantokens 中打开 lualatex 错误的办法?

作为软件包作者,我需要编写一本包含大量示例的手册。

现在我开始大量使用,lualatex以加快在 TeX(我的包,而不是手册)中需要很长时间的操作 - 并且我偶然发现了 lualatex 的一个未结票(错误?),当我尝试在手册中激活我的代码更改时它会阻止我。

背景:

我的手册中的示例应该是这样的

\begin{codeexample}[]
<code here>
\end{codeexample}

并且应该导致 (1) 一些逐字输出的列表和 (2) 执行的结果<code>。我想输入一次列表(仅一次)。

这是一个很好的用例\scantokens:我收集类别代码为 12(其他)的标记,以便将逐字输出显示为代码列表。此列表将包括语法突出显示和自动交叉引用。之后我使用\scantokens以将类别代码重置为其初始含义,以便我可以执行代码(以显示结果)。

最后一次调用\scantokens在 pdftex 中运行完美。但在 lualatex 中根本不起作用。

此问题已为人所知,请参阅http://tracker.luatex.org/view.php?id=733LuaTeX 中的 \scantokens

虽然我可以编写一个 lua 版本的软件包,并使用 pdftex 版本翻译手册,但我更愿意看到效果并记录特殊情况。最终,lua 版本可能会提供独特的功能。因此,我不想等到别人修复这个未解决的问题 - 我正在寻找解决方法。

有谁知道解决方法吗?

这个问题可以非常简单地表述,如链接的 tex.se 问题所指出的那样。我会将其表述为

\documentclass{standalone}

\begin{document}

Here should come text: \scantokens{^^JNamely this text}

\end{document}

pdftex 导致

在此处输入图片描述

而 luatex 导致

在此处输入图片描述

这与链接的问题相同。

但在我的用例中我需要换行符。

这是我的用例的一个简化(我想是最小的)示例,其中我逐字收集列表,然后重新分配 catcode 以执行列表。这个“执行列表”需要换行符,否则它将无法工作。并且:是的,我没有在这里排版列表(这是一个最小的示例)。

\documentclass{article}

\usepackage{pgfplotstable}

\makeatletter
% Define \find@example such that it doesn't destroy catcodes:
\begingroup
\catcode`|=0
\catcode`[= 1
\catcode`]=2
\catcode`\{=12
\catcode `\}=12
\catcode`\\=12 |gdef|find@example#1\end{codeexample}[|endofcodeexample[#1]]
|endgroup

\def\OLDNEWLINE{^^J}%
%% ATTEMPT (1*):
%% This here result in output of the first minimal. But it breaks the
%% second one.
%%\def\OLDNEWLINE{}%

% define \returntospace.
%
% It should define NEWLINE as {}, spaces and tabs as \space.
\begingroup
\catcode`\^=7
\catcode`\^^M=13
\catcode`\^^I=13
\catcode`\ =13%
\gdef\returntospace{\catcode`\ =13\def {\space}\catcode`\^^I=13\def^^I{\space}\catcode`\^^M=13\def^^M{\OLDNEWLINE}}%
% 
% ATTEMPT (2*):
%\gdef\returntospace{\catcode`\ =13\def {\space}\catcode`\^^I=13\def^^I{\space}\catcode`\^^M=13}%
\endgroup

\def\codeexample[#1]{%
    \parindent0pt
    \begingroup%
    \par%
    \medskip%
    \let\do\@makeother%
    \dospecials%
    \obeylines%
    \@vobeyspaces%
    \catcode`\^^M=13 %
    \find@example}
\def\endofcodeexample#1{%
    \endgroup%
    {%
      \returntospace%
      \xdef\code@temp{#1}% removes returns and comments
    }%
    %
    % ATTEMPT (2*): This here fixes the first minimal example together with (2*):
    %\catcode`\^^M=9 % 9 == ignore
    \expandafter\scantokens\expandafter{\code@temp}%
  \end{codeexample}
}

\makeatother



\begin{document}

This should result in the picture:
\begin{codeexample}[]
\begin{tikzpicture}
    \draw[red,->] (0,0) -- (1,1);

    \draw[green] (0,1) -- (1,0);
\end{tikzpicture}
\end{codeexample}

This should result in the table: 
\begin{codeexample}[]
\pgfplotstabletypeset{%
A B
2 3
4 5
}
\end{codeexample}
\end{document}

pdftex 生成预期结果,即

在此处输入图片描述

而 luatex 输出是

在此处输入图片描述

我已经尝试了代码中列出的几件事。我已经有了使用

\scantokens{\def\CONTENT{<sequence of 'other' catcodes}}

并使用“搜索和替换”例程来\CONTENT替换每个出现的换行符 - 嗯,我不知道用什么。简单的搜索和替换例程将无法处理此宏中的花括号。

我使用过 Tex live 2013(2014 目前我的硬盘装不下)。lua 票处于“新”状态,因此我并不期待有用的更新。

那么:有人知道我如何采用此代码示例代码来(a)收集两个示例的列表和(b)成功执行两个列表吗?没有修改这样的列表?

答案1

除了\scantokens\expandafter{\code@temp},您还可以将字符串传递给 Lua,让它在新行和tex.print每行处拆分字符串。tex.print仅调用一次将产生一行输入,并且无论使用多少 catcode 技巧,TeX 都无法表现得像有多行。

因此,我在下面的完整示例中使用以下 Lua 代码:

local s = "\luaescapestring{\code@temp}"
for line in s:gmatch("[^\string\n]+") do
  tex.print(line)
end

事实上,该代码并不能完全替代\scantokens。更准确的替代应该是以下代码,它处理 的值\newlinechar。如果它是负数(好吧,我还应该测试它是否太大),则直接输出字符串。否则,将变量设置newline为换行符(作为 Lua 字符串),可能带有转义%,然后定义一个模式,该模式与换行符以外的任何一个或多个字符序列相匹配(实际上,我刚刚意识到当一行中有两行新行时,这将失败),并通过 打印每个这样的序列tex.print

\long\def\myscantokens#1{\directlua{%
  local s = "\luaescapestring{\detokenize{#1}}"
  if \the\newlinechar < 0 then
    tex.print(s)
  else
    local newline = string.char(\the\newlinechar)
    if not newline:match("\string\%w") then
      newline = "\string\%" .. newline
    end
    local pattern = "[^" .. newline .. "]+"
    for line in s:gmatch(pattern) do
      tex.print(line)
    end
  end}}

无论如何,在这里我将使用更简单的代码,因为它似乎适合您的情况。

\documentclass{article}

\usepackage{pgfplotstable}

\makeatletter
% Define \find@example such that it doesn't destroy catcodes:
\begingroup
\catcode`|=0
\catcode`[= 1
\catcode`]=2
\catcode`\{=12
\catcode `\}=12
\catcode`\\=12 |gdef|find@example#1\end{codeexample}[|endofcodeexample[#1]]
|endgroup

\def\OLDNEWLINE{^^J}%

% define \returntospace.
%
% It should define NEWLINE as {}, spaces and tabs as \space.
\begingroup
\catcode`\^=7
\catcode`\^^M=13
\catcode`\^^I=13
\catcode`\ =13%
\gdef\returntospace{\catcode`\ =13\def {\space}\catcode`\^^I=13\def^^I{\space}\catcode`\^^M=13\def^^M{\OLDNEWLINE}}%
\endgroup

\def\codeexample[#1]{%
    \parindent0pt
    \begingroup%
    \par%
    \medskip%
    \let\do\@makeother%
    \dospecials%
    \obeylines%
    \@vobeyspaces%
    \catcode`\^^M=13 %
    \find@example}
\def\endofcodeexample#1{%
    \endgroup%
    {%
      \returntospace%
      \xdef\code@temp{#1}% removes returns and comments
    }%
    \directlua
      {%
        local s = "\luaescapestring{\code@temp}"
        for line in s:gmatch("[^\string\n]+") do
          tex.print(line)
        end
      }%
  \end{codeexample}
}
\makeatother



\begin{document}

This should result in the picture:
\begin{codeexample}[]
\begin{tikzpicture}
    \draw[red,->] (0,0) -- (1,1);

    \draw[green] (0,1) -- (1,0);
\end{tikzpicture}
\end{codeexample}

This should result in the table: 
\begin{codeexample}[]
\pgfplotstabletypeset{%
A B
2 3
4 5
}
\end{codeexample}
\end{document}

相关内容