作为软件包作者,我需要编写一本包含大量示例的手册。
现在我开始大量使用,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=733和LuaTeX 中的 \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}