The Luatex Way: \Framed
Total Page:16
File Type:pdf, Size:1020Kb
The LuaTEX way: \framed Hans Hagen Pragma ADE http://pragma-ade.com Abstract ConTEXt's \framed macro has many flexible options for typesetting a paragraph. This short note discusses its reimplementation in Lua for ConTEXt MkIV. 1 \framed and its width Here the outer \hsize was made a bit smaller. As you can see the frame is determined by the widest One of the more powerful commands in ConTEXt is \framed. You can pass quite a few parameters line. Because it was one of the first features we that control the spacing, alignment, backgrounds needed, the code in ConTEXt that is involved in de- and more. This command is used all over the place termining the maximum natural width is pretty old. (although often hidden from the user) which means It boils down to unboxing a \vbox and stepwise grab- that it also has to be quite stable. bing the last box, penalty, kern and skip. That is, Unfortunately, there is one nasty bit of code we unwind the box backwards. that is hard to get right. Calculating the height of a However, one cannot grab everything; or, in T X speak: there is only a limited number of box is not that complex: the height that TEX reports E is indeed the height. However, the width of box is \lastsomething commands. Special nodes, such as determined by the value of \hsize at the time of whatsits, cannot be grabbed and make the analyzer typesetting. The actual content can be smaller. In abort its analysis. There is no way that we can solve the \framed macro by default the width is calculated this in traditional TEX and in ConTEXt MkII. automatically. 2 \framed with LuaTEX \framed So how about LuaT X and ConT Xt MkIV? The [align=middle,width=fit] E E {Out beyond the ethernet the spectrum spreads macro used in the \framed command is: \unknown} \doreshapeframedbox{do something this shows up as (taken from ‘Casino Nation' by with \box\framebox} Jackson Browne): In LuaTEX we can manipulate box content at Out beyond the ethernet the Lua level. Instead of providing a truckload of ex- the spectrum spreads . tra primitives (which would also introduce new data types at the TEX end) we delegate the job to Lua. Or take this quote (from ‘A World Without Us' \def\doreshapeframedbox by Alan Weisman): {\ctxlua{commands.doreshapeframedbox \hsize=.6\hsize (\number\framebox)}} \framed [align=middle,width=fit] Here \ctxlua is our reserved instance for Con- {\input weisman } TEXt, and commands provides the namespace for This gives a multi-line paragraph: commands that we delegate to Lua (so, there are Since the mid-1990s, humans more of them). The amount of Lua code is far have taken an unprecedented smaller than the TEX code (which we will not show step in Earthly annals by here; it's in supp-box.tex if you want to see it). introducing not just exotic function commands.doreshapeframedbox(n) flora or fauna from one if tex.wd[n] ~= 0 then ecosystem into another, but local hpack = node.hpack actually inserting exotic genes local free = node.free into the operating systems of local copy = node.copy_list individual plants and animals, local noflines, lastlinelength, width = 0,0,0 where they're intended to do local list = tex.box[n].list exactly the same thing: copy local done = false themselves, over and over. for h in node.traverse_id('hlist',list) do done = true 462 TUGboat, Volume 29 (2008), No. 3 — TUG 2008 Conference Proceedings The LuaTEX way: \framed local p = hpack(copy(h.list)) we repack the content again, this time permanently. lastlinelength = p.width Now we use the maximum encountered width which if lastlinelength > width then is forced by the keyword exactly. Because all glue is width = lastlinelength still present we automatically get the desired align- end ment. We create local shortcuts to some node func- p.list = nil tions which makes it run faster; keep in mind that free(p) this is a core function called many times in a regular end if done then ConTEXt job. if width ~= 0 then In looking at ConTEXt MkIV you will find quite for h in node.traverse_id('hlist',list) do a lot of Lua code and often it looks rather complex, if h.width ~= width then especially if you have no clue why it's needed. Think h.list = hpack(h.list,width,'exactly') of OpenType font handling which involves locating h.width = width fonts, loading and caching them, storing features and end later on applying them to node lists, etc. end However, once we are beyond the stage of de- end veloping all the code that is needed to support the tex.wd[n] = width basics, we will start doing the things that relate more end to the typesetting process itself, such as the previous -- we can also work with lastlinelength end code. One of the candidates for a similar Lua-based end solution is for instance column balancing. From the previous example code you can deduce that manipu- In the first loop we inspect all lines (nodes with lating the node lists from Lua can make that easier. type hlist) and repack them to their natural width Of course we'll be a few more years down the road with node.hpack. In the process we keep track of by then. the maximum natural width. In the second loop TUGboat, Volume 29 (2008), No. 3 — TUG 2008 Conference Proceedings 463.