在 LuaLaTeX 中,如何将环境的内容逐字传递给 Lua?

在 LuaLaTeX 中,如何将环境的内容逐字传递给 Lua?

在 LuaLaTeX 中,我该如何捕获环境内容以供 Lua 逐字处理?例如,考虑类似

\begin{foobar}
  Hello {World}
\end{foobar}

我希望能够获取环境的内容并将其传递给 Lua,如下所示

foobar("  Hello {World}\n")

(然后 Lua 最终会将处理后的版本传回 LaTeX,但我大概可以处理这个问题)。

答案1

进入时启动“录制”模式\begin{foobar},关闭环境时结束录制模式。这样,您就获得了纯缓冲区内容。

\documentclass{article}
\usepackage{luacode}
\begin{luacode*}
do 
  local mybuf = ""
  function readbuf( buf )
    mybuf = mybuf .. buf .. "\n" 
  end
  function startrecording()
    luatexbase.add_to_callback('process_input_buffer', readbuf, 'readbuf')
  end

  function stoprecording()
    luatexbase.remove_from_callback('process_input_buffer', 'readbuf')
    local buf_without_end = mybuf:gsub("\\end{foobar}\n","")
    print(string.format("Lua: %q", buf_without_end))
  end
end
\end{luacode*}
\begin{document}
  \newenvironment{foobar}{\directlua{startrecording()}}{\directlua{stoprecording()}}
\begin{foobar}
    Hello {World}
\end{foobar}

\end{document}

答案2

在 ConTeXt 中,您可以简单地使用缓冲区来实现这一点。

\def\startfoobar
    {\definebuffer[foobar][startfoobar][stopfoobar]}

\def\stopfoobar
    {\ctxlua{userdata.luafunction(buffers.getcontents('foobar'))}

然后该函数userdata.luafunction将接收环境的内容。

查看ConTeXt 维基查看更多示例。

答案3

有点晚了,但这个修复https://tex.stackexchange.com/users/243/topskip的答案可以完成这项工作:

回答评论中的问题:

在 topskip 的回答中你好世界仍会写入 pdf 文件,这通常不是人们想要的。所以我采纳了他的答案并进行了更改,如果读取的行不包含“\end{foobar}”,则不会向 tex 解释器返回任何内容,但如果它包含“\end{foobar}”,则会将其吐回(通过 nil 返回值)tex 解释器,然后结束 foobar 环境。如果“\end{foobar}”行不会返回,则 tex 永远不会结束环境,这显然不是您想要的。

该示例仍不完善,因为如果同一行上“\end{foobar}”之前有文本,它就不会给出所需的结果。

\documentclass{article}
\usepackage{luacode}
\begin{luacode*}
do 
  local mybuf = ""
  function readbuf( buf )
   print("buf=" .. buf)
    i,j = string.find(buf,"\\end{foobar}")
    print(i,j)
    if i==nil then
     mybuf = mybuf .. buf .. "\n" 
     print("[" .. mybuf .. "]")
     return ""
    else 
    return nil
    end
   end

  function startrecording()
    luatexbase.add_to_callback('process_input_buffer', readbuf, 'readbuf')
  end

  function stoprecording()
    luatexbase.remove_from_callback('process_input_buffer', 'readbuf')
    local buf_without_end = mybuf:gsub("\\end{foobar}\n","")
    print(string.format("Lua: %s", buf_without_end))
  end
end
\end{luacode*}

\begin{document}
  \newenvironment{foobar}{\directlua{startrecording()}}{\directlua{stoprecording()}}
\begin{foobar}
    Hello {World}
\end{foobar}

\end{document}

相关内容