Lualatex 编译卡住

Lualatex 编译卡住

我正在尝试使用 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 错误。\draw

总的来说,这是一个很好的例子,说明了为什么在 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')}}

但我想您可能想将多个函数放在同一个文件中。)

相关内容