There are two questions here. You should consider asking one question at a time for your next posts.
Now to the Lua code environment. Don't use any of them if you can. Just do
\directlua{ require("myfile") }
and put all of your Lua code in that file. See another answer for a list of directories TeX searches for the file myfile.lua
.
If for some reason you can't do that (when you are only allowed to ship only one file for example) you should use the environment luacode*
(with *
) from the luacode package. That has the safest character catcodes. That means you can say something like:
\begin{luacode*}
texio.write_nl("This is a string with\n a newline in it")
tex.print(-2, string.format( "5 %% 4 is %d ", 5 % 4))
\end{luacode*}
(You need the -2
as the first argument to tex.sprint()
, because the %
sign (resulting from the double %%
is interpreted from TeX as a comment sign after the environment closes. TeX sees at the end of the environment 5 % 4 is 1
and treats the %
as the end of input. So you need to tell TeX that this %
is a regular character. You have two choices: either pass TeX a string like this: string.format("5 \\%% 4 is ...")
so that TeX sees 5 \% 4 is ...
as you would do with normal text or make %
a normal letter, so TeX does not recognize it as a comment sign. To do that you have to change the category code. The easiest way is to assign the special catcode table -2 to tex.print()
. It is a safe catcode table, no characters have a special meaning.)
If you need to use TeX macros in Lua code, use the luacode
environment (without *
):
\begin{luacode}
local current_page = tonumber(\thepage)
texio.write_nl("We are on page " .. current_page)
\end{luacode}
And if you need to put your code in a command, use \luaexec
:
\newcommand\myrepeat[2]{%
\luaexec{
for i=1,#1 do
tex.sprint("\luatexluaescapestring{#2}")
end
}}
\myrepeat{4}{Hello world}
(you can't use the environments directly in a \newcommand
, but you could use \luacodestar
... \endluacodestar
if you really want the environment functionality). The \luatexluaescapestring{}
is necessary to escape input characters like "
that would be harmful to the Lua string.
You have also asked if there is a shortcut such as the $
...$
for math typesetting. No, there is none. IMO that is not such a big problem, as Lua code (in practice, but YMMV) is only used at a few points (with macros or with environments for example) and not so much in running text. Mostly in packages. (See the documentation to the luacolor package for example. Even if you don't understand the package in full detail at the first glance, you can see where the TeX code is with the \directlua
calls, aliased in the example to \LuaCol@directlua
and how the Lua code is separated from it in another file. See that there are only very few lines of Lua code inside the \LuaCol@directlua
commands? In my opinion we can learn a lot from this code, as Heiko Oberdiek is an excellent package writer.)
Now to your second question about Saving variables. If you don't declare your variables local, they are accessible in all Lua chunks. But you are asking to pass Lua code to TeX. You can do this for example:
\begin{luacode*}
tex.sprint("\setcounter{mycounter}{" .. my_lua_value .. "}")
\end{luacode*}
to create a \setcounter
command with your value. Or you can use the tex.count
Lua interface:
\begin{luacode*}
tex.count[10] = my_lua_value
\end{luacode*}
and your value is in \count10
. But this is a bit dangerous as you have to be certain to use a free counter.
When you write
\newcommand{\iterate}[2]{
\directlua{
for i=1,#1,1 do
tex.print(\\compare{i}{#2})
end
}
}
The Lua process sees
for i=1,#1,1 do
tex.print(<the result of \compare>)
end
What you need to do is something like that:
\newcommand\iterate[2]{%
\luaexec{
for i=1,#1 do
tex.print(string.format("\\compare{\%d}{#2}",i))
end
}
}
\iterate{3}{2}
(luaexec is from the luacode package) This prints "\compare{1}{2}
\compare{2}{2}
\compare{3}{2}
" into TeX's input string and that gets evaluated. This works because \\
generates a backslash and it is separate from the word "compare". It's a hack and I don't recommend that. Please see How to do a 'printline' in LuaTeX for more info.
This is an experiment on "reevaluating":
For example: if you write
\documentclass[a4paper]{article}
\usepackage{luacode}
\begin{document}
\begin{luacode*}
tex.sprint("%hello")
\end{luacode*}
\end{document}
TeX will see %hello
and interprets it as a comment and thus no output file will be generated.
When you write this instead (see the -2 as the first argument to tex.print())
\documentclass[a4paper]{article}
\usepackage{luacode}
\begin{document}
\begin{luacode*}
tex.sprint(-2,"%hello")
\end{luacode*}
\end{document}
tex sees %hello, but the % has a "safe" category code. If the first argument to tex.print is a number, it will be taken as a catcode table. What I want to show: TeX reads the result of the \directlua{}
call.
Best Answer
Short answer: You have no other choice but using some kind of directlua/coroutine trick.
Longer answer: It doesn't work that way if I am correct. I can show a trick I have been using for quite some time (you mention the coroutine, so you might already use that, but for the record I'll write it down here). The problem is, as is pointed out in the question, that LuaTeX (the TeX side) does not execute the
\directlua
"command" until the closing brace}
.So, let's assume you are building a box of some kind and want to find out how big the box is. The simple approach does not work:
because TeX has not typeset the box when accessing the width of the box. So what you need to do is
This soon gets ugly, because the control flow is still on TeX's side. If you need more and more Lua code, you want to have something like a
directtex("...")
function from Lua. There is none, but you can us the mentioned trick with coroutines to do this. coroutines is a programming concept in Lua (and other languages) which lets you jump forth and back between two places in a program. So the idea is: jump into the Lua code, and go back when you need TeX and immediately go back to your Lua code where you were before.The idea is to create a function
main_loop()
and create a coroutine with this argument. Then you create a coroutine with this function as the entry point:co = coroutine.create(main_loop)
and jump into the coroutine (themain_loop()
function) withcoroutine.resume(co)
. Now when in Lua code, you can saycoroutine.yield("\\some\\TeX\\code")
and the control flow jumps back to the place where you calledcoroutine.resume()
. In other words (document.tex
):and
luacode.lua
:The heart of this is the TeX-loop around the
coroutine.resume
andtex.sprint()
. To jump out of this infinite loop, I have this new booleancontinue
. Now you have the control flow on the Lua side of your program and you can choose to go back to TeX whenever you need to. Just end your program withdirecttex("\\continuefalse")
and the loop will end.There is a drawback however. Error handling is now really awful. If you have an error in your Lua code, the computer blows up or the world will end, but LuaTeX might keep on running. A solution to get a better error handling is to use the
pcall()
lua function:But this will not catch the case where you say:
directtex("\\csname")