# [luatex] Turning a string into a list of nodes.

Paul Isambert zappathustra at free.fr
Thu Nov 18 21:52:10 CET 2010

Hello all,

I've been trying to devise a Lua function which, when fed a string, returns a
list of nodes. The application I have in mind is line numbering, counting lines
in the post_linebreak_filter and adding an \hbox with the number to lines that
are a multiple of a given number. Everything should be done in Lua, and thus the
counter must be converted to a list of nodes. I.e. the following should be
possible:

mylist = string_tolist(tostring(linecounter))

And more generally (there might be other applications beside line numbering):

mylist = string_tolist("Blah blah.")

I've come up with the code below. It does exactly that (given it's fed ASCII,
for it's not supposed to be complete now), but I find it quite convoluted: it
analyzes the string and turns each character into a node. And discretionaries
can't be inserted.

And here come the questions: Have I missed a definitely simpler way to do what I
want? If not, any suggestion on the code below? Do you think I should
feature-request Taco for a hard-coded function, capitalizing on his upcoming
available time and bad conscience? :)

Best,
Paul

-- Turns a character into a node.
local function create_glyph (char, fnt)
local glyph = font.getfont(fnt).characters[string.byte(char)]
local glyph_node = node.new(37, 0)
-- Could use glyph.name with PS fonts.
glyph_node.char = string.byte(char)
glyph_node.font = fnt
glyph_node.lang = tex.language
glyph_node.left, glyph_node.right = tex.lefthyphenmin, tex.righthyphenmin
glyph_node.uchyph = tex.uchyph
glyph_node.xoffset, glyph_node.yoffset = 0, 0
-- These produce an error message if one tries to set them.
--  glyph_node.width = glyph.width
--  glyph_node.height = glyph.height
--  glyph_node.depth = glyph.depth
glyph_node.expansion_factor = glyph.expansion_factor
return glyph_node
end

-- Creates a skip node.
local function create_skip (fnt)
local skip = node.new(10, 0)
local spec = node.new(47)
spec.width = font.getfont(fnt).parameters.space
spec.stretch = font.getfont(fnt).parameters.space_stretch
spec.shrink = font.getfont(fnt).parameters.space_shrink
spec.stretch_order = 0
spec.shrink_order = 0
skip.spec = spec
return skip
end

-- Returns the first character of a string and
-- the rest of the string.
local function string_pop(str)
local first_char
local new_string = string.gsub(str, "(.)",
function (match)
first_char = match
return ""
end, 1)
return first_char, new_string
end

function string_tolist (str, fnt)
-- The font is optional, the current one is used if none is given.
local Font = fnt or font.current()
local char, str = string_pop(str)
while char do
local glyph
if char == " " then
glyph = create_skip(Font)
else
glyph = create_glyph(char, Font)
end
glyph.prev = prev
if prev then
prev.next = glyph
else
end
prev = glyph
char, str = string_pop(str)
end
-- How can one insert discretionaries in the list?
node.ligaturing(item)
end