使用以下宏重新定义 lua 块的 catcode,使 tex 文件内部的 lua 编程更加自然,但存在缺陷:
\def\lua{%
\bgroup
\catcode`\\=12
\catcode`\{=12
\catcode`\}=12
\catcode`\^^M=12
\catcode`\#=12
\catcode`\~=12
\catcode`\%=12
\catcode`\_=12
\catcode`\@=12
\doluacode
}
\bgroup
\catcode`\|=0
\catcode`\^^M=12 %
\catcode`\\=12 %
|long|gdef|doluacode#1^^M#2\endlua{|directlua{#2}|egroup}%
|egroup
因为它重新定义了代码,所以它也会重新定义 tex.print 输出的代码。以下代码将失败
\lua
tex.print("\\mymacro")
\endlua
因为\
被解释为 catcode 为 12。
有什么方法可以让 tex.print 恢复使用原始 tex catcodes,这样打印 tex 内容就可以了没有必须手动重新定义每个字符(当您在 lua 中以编程方式生成 tex 代码时这显然不起作用)。
也就是说,我只想简单地运行上面的代码并进行少量修改并使其正常工作,而不必执行诸如 tex.print(0, "\") tex.print("mymacro") 之类的操作,这对于以编程方式生成的 tex 再次不起作用。
我所拥有的唯一方法是创建一个新的打印函数,扫描字符串并转换 cat 代码,但希望有更好的方法?
答案1
ConTeXt 提供\startluacode
和\stopluacode
宏,它们提供的功能与您的\lua
...\endlua
宏相同。这两个宏之间的主要区别在于,ConTeXt 宏在调用之前会切换到正常的 catcode \direclua
。以下代码是从luat-ini.mkiv
%D A few more goodies:
\unexpanded\def\startlua {\luat_start_lua } \let\stoplua \relax % tex catcodes
\unexpanded\def\startluacode{\luat_start_lua_code} \let\stopluacode\relax % lua catcodes
% It might makes sense to have a \type {\directelua} so that we can avoid
% the \type {\normalexpanded} around \type {\directlua}. Something to discuss
% in the team.
\def\luat_start_lua
{\begingroup
\obeylualines
\luat_start_lua_indeed}
\def\luat_start_lua_indeed#1\stoplua
{\normalexpanded{\endgroup\noexpand\directlua\zerocount{#1}}}
\def\luat_start_lua_code
{\begingroup
\obeylualines
\obeyluatokens
\luat_start_lua_code_indeed}
\def\luat_start_lua_code_indeed#1\stopluacode
{\normalexpanded{\endgroup\noexpand\directlua\zerocount{#1}}}
其中\obeylualines
等于\relax
(从以前的定义中遗留下来的?)并且\obeyluatokens
定义为
\appendtoks
\let\\\lualetterbackslash
\let\|\lualetterbar \let\-\lualetterdash
\let\(\lualetterlparent \let\)\lualetterrparent
\let\{\lualetterlbrace \let\}\lualetterrbrace
\let\'\lualettersquote \let\"\lualetterdquote
\let\n\lualettern \let\r\lualetterr
\let\f\lualetterf \let\t\lualettert
\let\a\lualettera \let\b\lualetterb
\let\v\lualetterv \let\s\lualetters
\let\1\lualetterone \let\2\lualettertwo
\let\3\lualetterthree \let\4\lualetterfour
\let\5\lualetterfive \let\6\lualettersix
\let\7\lualetterseven \let\8\lualettereight
\let\9\lualetternine \let\0\lualetterzero
\to \everyluacode
\def\obeyluatokens
{\setcatcodetable\luacatcodes
\the\everyluacode}
答案2
请参阅我的回答我应该将哪个 Lua 环境与 LuaTeX(LuaLaTeX)一起使用?。精髓在于:不要用于\directlua
编写 Lua 代码。为什么?因为你遇到了你遇到的问题和其他一些问题(例如错误消息上的行号)。你可以查看软件包luacode
以了解如何正确执行 catcode,但如果你只是想编写 Lua 代码,那就没有必要了。
答案3
通过使用\beginblock
包装 catcode 并\endblock
在实际传递给 lua 之前恢复它们。允许参数\lua
由 catcode 修复,但由于\endblock
发生在\directlua
调用之前,因此 catcode 被恢复,因此 lua 代码的输出使用原始 catcode。
% defines a \lua ... \endlua block for executing luacode
\def\lua{%
%\directlua{print("\noexpand\n")}% Print out a new line character each time a new lua block is used to force starting on a new line(else it may not)
\bgroup
\begingroup
\catcode`\\=12
\catcode`\{=12
\catcode`\}=12
\catcode`\^^M=12
\catcode`\#=12
\catcode`\~=12
\catcode`\%=12
\catcode`\_=12
\catcode`\@=12
\catcode`\|=0
\doluacode
}
\bgroup
\catcode`\|=0
\catcode`\^^M=12 %
\catcode`\\=12 %
|long|gdef|doluacode#1^^M#2\endlua{|endgroup|directlua{#2}|egroup}%
|egroup