# Assign Box Register in Lua

I would like to implement the following in Lua, for various reasons. Recursion in a macro language is bad idea - the definition below exceeds the input stack size. I want to avoid TeX for a bisection font size search. Etc.

You can ignore this. The MWE is further down.

% Exceeds input stack size.
\newbox\fittedtextbox
% {1 width} {2 height} {3 starting font size} {4 font step} {5 minimum font size}
\def\startfittedtext#1#2#3#4#5{%
\def\boxsize#1#2#3#4#5{%
\setbox\fittedtextbox\vbox{%
\definebodyfontenvironment[#3]
\switchtobodyfont[#3]
\hsize=#1
\emergencystretch=1ex
\tolerance=4000
\hyphenpenalty=8000
\getbuffer[fittedtext]}}
\def\stopfittedtext{%
\stopfittedtextargs{#1}{#2}{#3}{#4}{#5}}
\ruledvbox to #2{\unvbox\fittedtextbox}}
\def\stopfittedtextargs#1#2#3#4#5{%
\boxsize{#1}{#2}{#3}{#4}{#5}
\ifdim\ht\fittedtextbox>#2
\stopfittedtextargs{#1}{#2}{\dimexpr#3-#4\relax}{#4}{#5}
\fi}
\dostartbuffer[fittedtext][startfittedtext][stopfittedtext]}

\startfittedtext{7cm}{7cm}{12pt}{1pt}{1pt}
\input knuth
\stopfittedtext


The core operation is the assignment to a box register. This is what I need to replicate in Lua.

\setbox0=\vbox{...}


As far as I can tell ConTeXt doesn't provide the appropriate Lua API. The context.* function are output functions. The vbox will be outputted and tex.box[0] receives the return value of context.vbox, probably nil (haven't checked).

\startluacode
tex.box[0] = context.vbox(function() context.input("knuth") end)
\stopluacode


This is more subtle. The TeX stream is only executed when the Lua code block exits. So tex.box[0] references the value from before the Lua code block.

\def\coreop#1{\setbox0=\vbox{#1}}
\startluacode
context.coreop(function() context.input("knuth") end)
context("%spt", tex.box[0].height/65536)
\stopluacode


Same problem with this:

\startluacode
context("\\setbox0=\\vbox{\\input knuth }")
context("%spt", tex.box[0].height/65536)
\stopluacode


I did find this email[1] but wow, that's not what I want. It did mention that a higher-level API is on the horizon. Hopefully similar to context.vbox but returning a node (is this what a register is?) rather than outputting a box. If it has materialized, I'd appreciate an example. If not, there must be some workaround. A way to flush the TeX stream, or anything else.

There is a function tex.runtoks which runs a local TeX loop:

\starttext
\def\coreop#1{\setbox0=\vbox{#1}}
\startluacode
tex.runtoks(function()
context.coreop(function() context.input("knuth") end)
end)
context("%spt", tex.box[0].height/65536)
\stopluacode
\stoptext

• Interesting. Re. tex.runtoks: You have to make sure that at the end TEX is in a sane state and this is not always trivial. I wonder what this means in terms of a function that should accept any valid TeX. – user19087 Mar 26 at 1:10
• @user19087 Well, as long as you "only" do \coreop where everything is wrapped in \vbox{...} anyway it should be safe. – Marcel Krüger Mar 26 at 1:16
• Ironically I am keeping as much TeX out of Lua as possible. Otherwise I have to deal with nested runtoks for converting ex to sp at the proper font size. Also searching for how to convert 1ex to sp isn't easy. Possibly put an "x" in a vbox and measure the height, but there are probably lots of gotchas for conforming to TeX's conversion. Could be another question if I used this approach. – user19087 Mar 26 at 17:27
• tex.runtoks(context.delayed.coreop(context.delayed.input("knuth"))) – Henri Menke Mar 27 at 6:34