1

How do I emulate the \message primitive in Lua code in LuaTeX? I want something like texio.write('foobarbaz'), but without the line break within the word foobarbaz.

Example with lualatex:

\typeout{1}
\message{hellofoobarbaz} \message{foobarbaz}
\message{foobarbaz} \message{foobarbaz}
\message{foobarbaz} \message{foobarbaz}
\message{foobarbaz} \message{foobarbaz}
\message{foobarbaz} \message{foobarbaz}
\message{foobarbaz} \message{foobarbaz}
\typeout{2}
\message{hello}
\directlua{texio.write('foobarbaz ') texio.write('foobarbaz ')}
\directlua{texio.write('foobarbaz ') texio.write('foobarbaz ')}
\directlua{texio.write('foobarbaz ') texio.write('foobarbaz ')}
\directlua{texio.write('foobarbaz ') texio.write('foobarbaz ')}
\directlua{texio.write('foobarbaz ') texio.write('foobarbaz ')}
\directlua{texio.write('foobarbaz ') texio.write('foobarbaz ')}
\directlua{texio.write('foobarbaz ') texio.write('foobarbaz ')}
\directlua{texio.write('foobarbaz ') texio.write('foobarbaz ')}
\directlua{texio.write('foobarbaz ') texio.write('foobarbaz ')}
\csname @@end\endcsname    

I get this output on the console:

1
hellofoobarbaz foobarbaz foobarbaz foobarbaz foobarbaz foobarbaz foobarbaz
foobarbaz foobarbaz foobarbaz foobarbaz foobarbaz
2
hellofoobarbaz foobarbaz foobarbaz foobarbaz foobarbaz foobarbaz foobarbaz fooba
rbaz foobarbaz foobarbaz foobarbaz foobarbaz foobarbaz foobarbaz foobarbaz fooba
rbaz foobarbaz foobarbaz )

The line is broken between fooba and rbaz. I want the line break before `fooba' instead.

  • texio.write('foobarbaz') would not normally put a linebreak within the word, tex wraps the output at a certain width if that is what you mean? But you posted no example? – David Carlisle Jan 17 at 23:44
  • @DavidCarlisle: Added an example which clarifies what I get and what I want. – pts Jan 17 at 23:57
  • is \directlua{tex.print('\string\\message{foobarbaz }') tex.print('\string\\message{foobarbaz }')} cheating? – David Carlisle Jan 18 at 0:39
  • @DavidCarlisle: My production Lua code is slow, I want to display progress updates. Using tex.print all the progress updates would be delayed after my Lua code finishes. So in this use case it's cheating. – pts Jan 18 at 1:03
5

There is no way to access the \message primitive from Lua. If you want to write to the log you can use the texio library as suggested in David's answer, or if you just want to write to the terminal, print will actually do fine.

You can however, use asynchronous communication between Lua and TeX using coroutines, as recently shown in

H. Hagen. Executing TeX in Lua: Coroutines. TUGboat, 39(1):41–43, 2018. https://www.tug.org/TUGboat/tb39-1/tb121hagen-exec.pdf

Here is some sample code which will sleep for 1 second and then print “Hello” and a counter to the terminal. This needs at least version 1.08.0 of LuaTeX for texio.closeinput().

\documentclass{article}
\usepackage{luacode}
\begin{luacode*}
local stepper = nil
local stack = {}
local fid = 0xFFFFFF
local goback = "\\luafunction" .. fid .. "\\relax"

function tex.resume()
    if coroutine.status(stepper) == "dead" then
        stepper = table.remove(stack)
    end
    if stepper then
        coroutine.resume(stepper)
    end
end

lua.get_functions_table()[fid] = tex.resume

function tex.yield()
    tex.sprint(goback)
    coroutine.yield()
    texio.closeinput()
end

function tex.routine(f)
    table.insert(stack, stepper)
    stepper = coroutine.create(f)
    tex.sprint(goback)
end
\end{luacode*}
\begin{document}

\begin{luacode*}
tex.routine(function()
        for i = 1, 10 do
            -- some long task
            os.sleep(1) -- sleep 1 second instead
            tex.sprint("\\message{Hello " .. i .. "!}")
            tex.yield()
        end
end)
\end{luacode*}

\end{document}
3

Perhaps

\typeout{1}
\message{hellofoobarbaz} \message{foobarbaz}
\message{foobarbaz} \message{foobarbaz}
\message{foobarbaz} \message{foobarbaz}
\message{foobarbaz} \message{foobarbaz}
\message{foobarbaz} \message{foobarbaz}
\message{foobarbaz} \message{foobarbaz}
\typeout{2}
\message{hello}
\directlua{texio.write('foobarbaz ') texio.write('foobarbaz ')}
\directlua{texio.write('foobarbaz ') texio.write('foobarbaz ')}
\directlua{texio.write('foobarbaz ') texio.write('foobarbaz ')}
\directlua{texio.write('foobarbaz ') texio.write('foobarbaz ')}
\directlua{texio.write('foobarbaz ') texio.write('foobarbaz ')}
\directlua{texio.write('foobarbaz ') texio.write('foobarbaz ')}
\directlua{texio.write('foobarbaz ') texio.write('foobarbaz ')}
\directlua{texio.write('foobarbaz ') texio.write('foobarbaz ')}
\directlua{texio.write('foobarbaz ') texio.write('foobarbaz ')}


\typeout{3}
\directlua{
col=0
function zz(s)
local l=string.len(s)
if(col+l > 75) then
col=0
io.write('\string\n')
end
io.write(s)
col=col+l
end
}
\directlua{zz('hello')}
\directlua{zz('foobarbaz ') zz('foobarbaz ')}
\directlua{zz('foobarbaz ') zz('foobarbaz ')}
\directlua{zz('foobarbaz ') zz('foobarbaz ')}
\directlua{zz('foobarbaz ') zz('foobarbaz ')}
\directlua{zz('foobarbaz ') zz('foobarbaz ')}
\directlua{zz('foobarbaz ') zz('foobarbaz ')}
\directlua{zz('foobarbaz ') zz('foobarbaz ')}
\directlua{zz('foobarbaz ') zz('foobarbaz ')}
\directlua{zz('foobarbaz ') zz('foobarbaz ')}


\csname @@end\endcsname 

managing the columns and linebreaking yourself (which does mean that you have to start the first one at a forced newline) it produces

1
hellofoobarbaz foobarbaz foobarbaz foobarbaz foobarbaz foobarbaz foobarbaz
foobarbaz foobarbaz foobarbaz foobarbaz foobarbaz
2
hellofoobarbaz foobarbaz foobarbaz foobarbaz foobarbaz foobarbaz foobarbaz foob
arbaz foobarbaz foobarbaz foobarbaz foobarbaz foobarbaz foobarbaz foobarbaz foo
barbaz foobarbaz foobarbaz 
3
hellofoobarbaz foobarbaz foobarbaz foobarbaz foobarbaz foobarbaz foobarbaz 
foobarbaz foobarbaz foobarbaz foobarbaz foobarbaz foobarbaz foobarbaz 
foobarbaz foobarbaz foobarbaz foobarbaz
  • 3
    zz invading lua now ;-) – Ulrike Fischer Jan 18 at 8:53
  • @UlrikeFischer I'll get you a UK keyboard so you can find z. – David Carlisle Jan 18 at 9:04
  • does not work if string has >75 chars (untested) – user4686 Jan 18 at 9:19
  • 1
    @jfbu define "work": the spec was not to linebreak the supplied string, if you put in a string longer than that then it does what it does, Clearly it must be user error not a bug in the supplied code:-) – David Carlisle Jan 18 at 9:34
  • it will only "work" at zzz stage, i.e. do the linebreak appropriately even for long strings – user4686 Jan 18 at 12:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.