# In LuaLaTeX, how do I pass the content of an environment to Lua verbatim?

In LuaLaTeX, how would I go about capturing the content of an environment for (verbatim) processing by Lua? For example, consider something like

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


I'd like to be able to take the content of the environment and pass it to Lua, as in

foobar("  Hello {World}\n")


(and Lua would then eventually pass the processed version back to LaTeX, but I can presumably handle that).

• If you think that one of the answers solves your problem, you should accept it. If it doesn't, it would be nice to hear what could be improved. – topskip Dec 16 '11 at 13:04

Start the "recording" mode when you enter \begin{foobar} and end it when you close the environment. That way you get the pure buffer contents.

\documentclass{article}
\usepackage{luacode}
\begin{luacode*}
do
local mybuf = ""
mybuf = mybuf .. buf .. "\n"
end
function startrecording()
end

function stoprecording()
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}

• Amazing! Why do you include the lua code inside a closure do...end? Just best practice in lua coding? – cjorssen Dec 14 '11 at 11:29
• @cjorssen I define a local variable mybuf (which act as a kind of global variable for these two functions) and I don't want it to be visible outside the scope of the functions where I use it (to avoid clashes). In this case it is actually not necessary as the do / end pair is implicitly given by the luacode environment, but I like the explicit scoping here so anyone can see "hey, there is something inside that scope that must not be visible outside". – topskip Dec 14 '11 at 11:44
• In your example: Is it also possible to suppress the TeX output of the contents of {foobar}? I.e. read the environement contents to Lua, but hide it from TeX? – arney Mar 24 '13 at 23:55
• @arney I am not sure (didn't try) - did you try to return nil or an empty string from readbuf()? – topskip Mar 25 '13 at 7:15
• @topskip I have an improvement to your answer to ask here : tex.stackexchange.com/questions/207500/… – Tarass Oct 16 '14 at 18:17

In ConTeXt, you can simply use buffers for this.

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

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


The function userdata.luafunction will then receive the contents of the environment.

See the ConTeXt wiki for more examples.

A bit late to the party, but this fix to https://tex.stackexchange.com/users/243/topskip's answer does the job:

in response to question in comments:

In topskip's answer Hello World is still written to the pdf file, which is not typically what one would want. So I've taken his answer and made the change that if the line read does not contain "\end{foobar}" then nothing is returned to the tex interpreter, but if it does contain "\end{foobar}" it gets spit back (via the nil return value) to the tex interpreter which then ends the foobar environment. If the "\end{foobar}" line would not get returned then tex would never end the environment, which is clearly not what you want.

The example is still imperfect in that it doesn't give the desired result if there is text before "\end{foobar}" on the same line.

\documentclass{article}
\usepackage{luacode}
\begin{luacode*}
do
local mybuf = ""
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()
end

function stoprecording()
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}