2

So far in my dealings with named tex boxes in luatex, I am able to set/get/copy its contents in lua code, but don't know how define new tex box in lua. The manual doesn't have a method explicitly meant for that (while it has all other box manipulation methods). Is there a way to do this in lua? Below is the skeleton of code to build upon. Function createbox is passed name of the box to be created, and it acts like calling \newsavebox (with name test).

\documentclass{article}

\begin{filecontents*}{texbox.lua}
    function createbox(boxname)
        if <box of name boxname does not exist> then -- luatex equivalent of ifcsname?
            tex.print("\\newbox\\" .. boxname)
        end
    end
\end{filecontents*}


\directlua{require"texbox.lua"}

\begin{document}

    \directlua{createbox('mybox')} % use lua method instead of using \newsavebox on tex side

    \setbox\mybox = \hbox{Hello World}

    \box\mybox

\end{document}

1
  • note that unlike \newcommand, \newbox and friends (following the tradition of plain tex) do not check that the csname is undefined, \newbox\frac will over-write \frac with no warning. – David Carlisle Oct 3 '20 at 8:28
5

Register allocation is a macro format defined thing so not in the luatex manual. You appear to be using lualatex so box allocation is count 14 (which happens to be the same as plain tex) and the following shows how they can be allocated from tex or lua in the same sequence.

You could check that the name (\luaboxa here) is new, but the tex defined \newbox does not do that (see the multiple calls to \newbox\zzz below) , you can use \newbox\frac or \newbox\section and break the document with no warning.

It does check that you have not run out of registers. Here I more or less directly re-implement the LaTeX \e@alloc macro in Lua. Now the function new_box also checks if the box of that name is already defined, if yes it doesn't allocate a new box register for it. This is the intended behavior requested in the question, and should also save one from accidentally allocating more than one box register for a given boxname.

\documentclass{article}


\newbox\texboxa
\typeout{texboxa: \number\texboxa}

\directlua{
function e_alloc(nm,c,ta,tb,cs)
    tex.setcount("global",c,tex.count[c]+1)
    e_check_alloc(c,ta,tb,nm)
    tex.setcount("global","allocationnumber",tex.count[c])
    token.set_char(cs,tex.count[c],"global")
    texio.write("log",cs .."=" .. tex.count[c])
end
function e_check_alloc(c,ta,tb,nm)
  if ( tex.count[c] >= ta) then
    if (tex.count[c] == ta)then
      tex.setcount("global",c,256)
      if(nm=="count") then
           tex.setcount("global",c,tex.count[c]+10)
      end
    end
    if(tex.count[c]>=tb) then
      error("No room for a new " .. nm)
    end
  end
end

% \insc@unt is a count register
% \float@count is a chardef token, accessed via .mode
function new_box(b)
  if not token.is_defined(b) then 
   e_alloc("box",14,tex.count["insc@unt"],token.create("float@count").mode,b)
  end
end
new_box("luaboxa")
}
\typeout{luaboxa: \number\luaboxa}

\newbox\texboxb
\typeout{texboxb: \number\texboxb}


\count14=198

% 199 256 257 with tex
%\newbox\zzz \typeout{zzz: \number\zzz}
%\newbox\zzz \typeout{zzz: \number\zzz}
%\newbox\zzz \typeout{zzz: \number\zzz}

% 199 199 199 -- better with Lua
\directlua{new_box("zzz")}\typeout{zzz: \number\zzz}
\directlua{new_box("zzz")}\typeout{zzz: \number\zzz}
\directlua{new_box("zzz")}\typeout{zzz: \number\zzz}

\begin{document}

\directlua{new_box("zzz")}\setbox\zzz=\hbox{Hello World}\copy\zzz\typeout{zzz: \number\zzz}

\directlua{new_box("zzz")}\setbox\zzz=\hbox{Foo World}\copy\zzz\typeout{zzz: \number\zzz}

\directlua{new_box("zzb")}\setbox\zzb=\hbox{Bar World}\copy\zzb\typeout{zzb: \number\zzb}

\directlua{new_box("zzz")}\setbox\zzz=\hbox{ooF World}\copy\zzz\typeout{zzz: \number\zzz}

\setbox\zzz=\hbox{Sham World}\copy\zzz\typeout{zzz: \number\zzz}
\copy\zzb\typeout{zzb: \number\zzb}

\end{document}

The terminal output is

texboxa: 45

luaboxa: 46
texboxb: 47

zzz: 199
zzz: 199
zzz: 199
zzz: 199
zzz: 199

zzb: 257
zzz: 199
zzz: 199
zzb: 257

showing how the allocation correctly jumps to the etex extended registers without over-writing the float boxes. It also shows that new box registers are not allocated for a boxname (if user tries to again create a box with same name), thus saving box register resources.

Compiled output is: Compiled output for updated code


Original Answer

The terminal output is

texboxa: 45
luaboxa: 46
texboxb: 47

from

\documentclass{article}


\newbox\texboxa
\typeout{texboxa: \number\texboxa}

\directlua{
tex.setcount("global",14,tex.count[14]+1)
token.set_char("luaboxa",tex.count[14],"global")
}
\typeout{luaboxa: \number\luaboxa}

\newbox\texboxb
\typeout{texboxb: \number\texboxb}


\begin{document}


\end{document}

You could check that the name (\luaboxa here) is new, but the tex defined \newbox does not do that, you can use \newbox\frac or \newbox\section and break the document with no warning. It does check that you have not run out of registers, so defining it as a function with error checking to match \newbox you could have

\directlua{
function new_box(b)
  if tex.count[14] > 65534 then
    error("No room for a new box register")
  else
    tex.setcount("global",14,tex.count[14]+1)
    token.set_char(b,tex.count[14],"global")
  end
end
new_box("luaboxa")
}

Note this is only safe if the box allocation has already passed 255, a more complete version that avoids over-writing float boxes would need to re-implement \e@alloc in Lua, to be added shortly.....

3
  • see for example the Lua allocators such as luatexbase.new_whatsit in ltluatex.lua in the latex base distribution. – David Carlisle Oct 3 '20 at 8:25
  • Looking at the first two if statements in e_check_alloc, I wonder if you intended to type something different in e_check_alloc. In the current form, e_check_alloc will execute anything only if tex.count[c] == ta, so why surround it with a superset condition check tex.count[c] >= ta? As a bonus, some documentation would also help. Thanks! – reportaman Oct 3 '20 at 21:12
  • 1
    @reportaman sorry got my if..end nesting messed up, fixed. The documentation is as for the tex one in ltplain.dtx (texdoc source2e pages 17-19 but I may add something here later, perhaps. – David Carlisle Oct 3 '20 at 21:30

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.