Marcel's answer resolved the original question. I have added followup questions from his answer under my original question. Followup questions begin with a similar block quote as this stating "Followup questions begin here:"
Am trying to learn luatex node library, and here's what I thought I would want to do as an experiment:
- Append a whatsit save_pos node to every line of text.
- Iterate over all the whatsis save_pos nodes to retrieve position of linebreaks/lineendings and either save it to some array to use at the end of page or beginning of next page.
I know how to do 1., though don't know how to do 2 (could not decipher a way to do that from luatex manual).
AFAIK, positions on page are only known after a certain point in the processing of page, so I cannot probably use a linebreak callback right away to know that information. Though I do not know how to traverse all the elements of the page (at the end of page building process, or of previous page at the beginning of next page) to get a list of positions of all linebreaks. Ideally I would like to traverse all elements on the page as save_pos could be placed anywhere (inside hbox, inside vbox, in main vertical list, header/footers, or textpos overlays, etc).
Here's my code so far:
\documentclass[notitlepage,letterpaper]{article} %\usepackage{lua-visual-debug} \usepackage[absolute]{textpos} \usepackage[letterpaper,left=0in,right=0in,top=1in,bottom=1in]{geometry} \usepackage[expansion=alltext,shrink=20,stretch=20]{microtype} \usepackage{fontspec} \usepackage{blindtext} %\setmainfont{Verdana} % Commented this as standard linux installs do not come with Verdana, check Marcel's comment to this question. \directlua{ function my_post_lb_filter(head,groupcode) local HLIST = node.id("hlist") % node.id for a line of text in vertical list for n in node.traverse(head) do % For every subnode within node head if n.id==HLIST then % If its a line of text local savepos = node.new("whatsit","save_pos") n.head = node.insert_after(n.head,node.tail(node.list),savepos) end end return head end luatexbase.add_to_callback('post_linebreak_filter', my_post_lb_filter, 'Play with luatex node library') } \begin{document} \raggedright \newbox\myoddvbox \newbox\myoddvboxsplit \global\setbox\myoddvbox=\vbox{{\hsize=2in \blindtext[1]\endgraf}}% \setbox\myoddvboxsplit=\vsplit\myoddvbox to 4cm \begin{textblock*}{0.5\linewidth}[0,0](2in,2in) \begin{minipage}[t][1cm][t]{0.5\linewidth}% \box\myoddvboxsplit% \end{minipage} \end{textblock*} \begin{textblock*}{0.5\linewidth}[0,0](5in,2in) \begin{minipage}[t][1cm][t]{0.5\linewidth}% \box\myoddvbox% \end{minipage} \end{textblock*} \null \newpage % replace following line with a iterate function to print all the positions from lastpage \the\lastxpos, \the\lastypos. \end{document} Followup questions begin here:
- What is the sequence of execution of late_lua nodes? Is it a FIFO model?
- What is the nature of data that can be acted on? Can we access and late process hlist node (for instance insert_to) from a latelua function? Or is it too late for that? What is the life of a hlist node anyway, is it freed after a page is shipped out?
- Can we pass arguments to a late_lua function? I tried passing arguments to the function
savepos.data = savepos_func("hello"), and the lua segfaults. - luatex manual says the type of
datafield of late_lua node can be either string or function. When would one assign a string to a late_lua node's data field? I tried assigning a lua stringsavepos.data = "hello world", and it gave a error during shipout[\latelua]:1: syntax error near 'world'. - What is the scope of code that goes in directlua? I tried to print the size of table
position_arrayusing\AtBeginShipoutof package\usepackage{atbegshi}, and it printsnilon terminal (code is simpleprint(tostring(table.getn(position_array)))in a\directluamacro). If I removelocalfrom the declarationlocal position_array = {}, then it prints the correct value of the array (while processing next page).- Why did you not select function getpos_and_reset to be local, while making function getpos_and_reset, and table position_array local?

datafield is a string it will be evaluated as a lua code so you can writesavepos.data = "savepos_func('hello')". But keep in mind that this function will run in some outer LUA scope so it needs to be global (this is just my experience)