我正在尝试使用 lualatex 生成 tikz 图像。但是,编译器卡住了,没有输出任何内容。下面是一个最小示例
\documentclass{standalone}
\usepackage{luacode}
\usepackage{tikz}
\newcommand{\drawaxes}{%
\directlua{%
tex.sprint("\draw[thick,red] (-1,0) -- (1,0)")
}
}
\begin{document}
\begin{tikzpicture}
%\draw[thick,red] (-1,0) -- (1,0);
\drawaxes;
\end{tikzpicture}
\end{document}
编译卡在:
[Loading MPS to PDF converter (version 2006.09.02).]
) (/usr/share/texlive/texmf-dist/tex/latex/oberdiek/epstopdf-base.sty
(/usr/share/texlive/texmf-dist/tex/latex/oberdiek/grfext.sty
(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/kvdefinekeys.sty))
(/usr/share/texlive/texmf-dist/tex/latex/oberdiek/kvoptions.sty
(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/kvsetkeys.sty
(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/etexcmds.sty)))
(/usr/share/texlive/texmf-dist/tex/latex/latexconfig/epstopdf-sys.cfg
^C))
! Interruption.
\path ^^@-\let \tikz@signal@path
=\tikz@signal@path \pgfutil@ifnextchar [{\tik...
l.14 \drawaxes
;
?
请注意,当我直接使用时,\draw
它工作正常。任何有关如何调试的提示都将不胜感激。
答案1
参数\directlua
始终会完全展开,因此\draw
会展开为\path
,从而展开为错误消息中的代码。这会进入无限循环,以防止在展开上下文中使用它。
\draw
为了解决这个问题,你必须在参数完全展开时避免展开\directlua
。为此,你可以使用例如\unexpanded
:
\newcommand{\drawaxes}{%
\directlua{\unexpanded{%
tex.sprint([[\draw[thick,red] (-1,0) -- (1,0)]])
}}
}
你可以看到我还必须用 替换引号[[]]
。在引号内,反斜杠启动转义序列,后跟 的"\draw"
特殊字符也是如此,这会导致另一个 TeX 错误。\d
raw
总的来说,这是一个很好的例子,说明了为什么在 LuaTeX 中内联编写 Lua\directlua
会导致很多问题。通过将 Lua 代码移到另一个文件或包luacode*
提供的环境中,可以避免大多数这些问题luacode
。
如果您更喜欢内联解决方案,该luacode
软件包还提供了\luaexec
命令。这允许您使用双反斜杠将 TeX 命令包含在常规 Lua 字符串中。因此您可以使用
\newcommand{\drawaxes}{%
\luaexec{
tex.sprint("\\draw[thick,red] (-1,0) -- (1,0)")
}
}
答案2
所以你已经定义了
\newcommand{\drawaxes}{%
\directlua{%
tex.sprint("\draw[thick,red] (-1,0) -- (1,0)")
}
}
之后,当 TeX 遇到 时\drawaxes
,它会将其替换为
\directlua {tex.sprint("\draw [thick,red] (-1,0) -- (1,0)") }
然后继续工作。现在它遇到了。如果你在 LuaTeX 手册中\directlua
查找原语的文档,它说:\directlua
原始 \directlua 用于立即执行 Lua 代码。语法如下
\directlua ⟨general text⟩ \directlua ⟨16-bit number⟩ ⟨general text⟩
⟨一般文本⟩是充分展开,然后输入到 Lua 解释器中。...
因此 TeX 会获取标记序列tex.sprint("\draw [thick,red] (-1,0) -- (1,0)")
并开始对其进行扩展。 到 的每个标记tex.sprint("
都保持原样(不扩展),但 会\draw
扩展为\path [draw]
。 并\path
扩展为
\let \tikz@signal@path=\tikz@signal@path \pgfutil@ifnextchar [{\tikz@check@earg }{\pgfutil@ifnextchar <{\tikz@doopt }{\tikz@@command@path }}
其中\tikz@signal@path
被定义为一个宏,它扩展为... \tikz@signal@path
本身!当你中断时,TeX 仍在反复扩展\tikz@signal@path
。
\errorcontextlines=100
如果您愿意,您可以在文件中添加类似的内容来看到所有这些内容.tex
,以便在错误消息中看到比您看到的更多的上下文:
! Interruption.
\path ->\let \tikz@signal@path
=\tikz@signal@path \pgfutil@ifnextchar [{\tikz@check@earg }{\pgfutil@ifnextchar <{\tikz@doopt }{\tikz@@command@path }}
\draw ->\path
[draw]
\drawaxes ->\directlua {tex.sprint("\draw
[thick,red] (-1,0) -- (1,0)") }
l.16 \drawaxes
;
?
(惯例是,在每对行中,第一行是 TeX 已读取的所有内容,第二行是尚未读取的内容。这是 TeX 内部输入堆栈的转储。)
添加\tracingmacros=1 \tracingonline=1
以查看 TeX 的努力工作。
您可以在不使用 LuaTeX 的情况下使用如下文档重现此错误:
\documentclass{standalone}
\usepackage{tikz}
\makeatletter
\edef\haha{\tikz@signal@path}
在任何其他引擎(pdfTeX 或 XeTeX)上也是如此。
(我不知道为什么\tikz@signal@path
被定义为扩展为自身;它是过来 前。
无论如何,解决方案是确保\directlua
获取您想要的实际 Lua 代码。TeX 宏有一些技巧,但最简单的方法是将尽可能多的 Lua 代码放在单独的文件中。(我的经验法则是:的内容\directlua{...}
应仅包含字母数字字符、()
和单引号。)
例如,输入以下内容draw.lua
:
function drawaxes()
tex.sprint([[ \draw[thick,red] (-1,0) -- (1,0) ]])
end
(请注意,按字面[[ ... ]]
意思处理字符串,而不必转义反斜杠)
您的.tex
文件可以是:
\documentclass{standalone}
\usepackage{luatex85}
\usepackage{tikz}
\directlua{dofile('draw.lua')}
\newcommand{\drawaxes}{\directlua{drawline()}}
\begin{document}
\begin{tikzpicture}
\drawaxes;
\end{tikzpicture}
\end{document}
(或者你可以只把这tex.sprint
一行放到文件中draw.lua
,然后
\newcommand{\drawaxes}{\directlua{dofile('draw.lua')}}
但我想您可能想将多个函数放在同一个文件中。)