[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 head, prev
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
head = glyph
end
prev = glyph
char, str = string_pop(str)
end
-- How can one insert discretionaries in the list?
for item in node.traverse(head) do
node.ligaturing(item)
end
for item in node.traverse(head) do
if item.next then
-- If the second argument isn't there, LuaTeX crashes.
node.kerning(item, item.next)
end
end
return head
end
More information about the luatex
mailing list