TeX - LaTeX Asked on January 11, 2021
This is a LuaTeX node-library/ node-list question.
In the following code, I am trying to typeset a manually crafted nodelist. To add a line break, I add a penalty node, and that works fine (i.e. the line breaks at that point). But when I add a vertical glue/kern after the linebreak, it doesn’t really add any vertical space. Where am I going wrong? What nodes are needed to tell the linebreak routine to add vertical space? Am expecting behavior similar to LaTeX’s macros vspace{25pt}
or [25pt]
.
Sidenote lua questions: 1) Is the
require
way of loading the lua file ok? I mean, what if I have alocal
variable name clash with another lua file that I load withrequire
, for instance variablelocal head
? 2) Instead of making the functions global, is there a way to call them with something likelinebreak.
prefix to avoid name clash with other lua files that have functions with same name?Update: The "Sidenote" questions above are now discussed as a separate question here, please ignore above "Sidenote lua questions" while reading this question as they are not relevant to it.
Screenshot (I expect additional 25pt or 50pt vertical space after first line):
linebreak.tex:
>>> lualatex linebreak.tex
documentclass{article}
directlua{require"linebreak.lua"}
begin{document}
raggedright
directlua{
initialize()
addchars('H')
addchars('e')
addchars('l')
addchars('l')
addchars('o')
addchars(' ')
addchars('W')
addchars('o')
addchars('r')
addchars('l')
addchars('d')
addpenalty(1,-10000) % Add line break, works fine!
addglue(1,25*65536) % XXX: Add vertical glue, doesn't work!
addkern(1,25*65536) % XXX: Add vertical kern, doesn't work!
addchars(' ')
addchars('H')
addchars('e')
addchars('y')
writeparagraph()
}
end{document}
linebreak.lua:
local glyph_id = node.id("glyph")
local glue_id = node.id("glue")
local kern_id = node.id("kern")
local penalty_id = node.id("penalty")
local current_font = font.current()
local font_parameters = font.getfont(current_font).parameters
local n, head, last
function addchars(c)
for s in string.utfvalues(c) do
local char = unicode.utf8.char(s)
if unicode.utf8.match(char,"%s") then
-- its a space
n = node.new(glue_id)
n.width = font_parameters.space
n.shrink = font_parameters.space_shrink
n.stretch = font_parameters.space_stretch
else -- a glyph
n = node.new(glyph_id)
n.font = current_font
n.subtype = 1
n.char = s
n.lang = tex.language
n.uchyph = 1
n.left = tex.lefthyphenmin
n.right = tex.righthyphenmin
end
last.next = n
last = n
end
return last
end
function addpenalty(s,p)
n = node.new(penalty_id)
n.subtype = s or 0
n.penalty = p or 0
last.next = n
last = n
return n
end
function addkern(s,p)
n = node.new(kern_id)
n.subtype = s or 0
n.kern = p or 0
last.next = n
last = n
return n
end
function addglue(s,a,b,c,d,e)
n = node.new(glue_id)
n.subtype = s
n.width = a or 0
n.stretch = b or 0
n.shrink = c or 0
n.stretch_order = d or 0
n.shrink_order = e or 0
last.next = n
last = n
return n
end
function initialize()
-- add parindent glue in the beginning, create head node
head = node.new("glue")
head.width = tex.parindent
last = head
end
function writeparagraph()
-- append a penalty and parfillskip glue at the end of list
addpenalty(0,10000)
addglue(15,0,tex.parfillskip.stretch,tex.parfillskip.stretch_order)
-- create prev pointers
node.slide(head)
-- hyphenate
lang.hyphenate(head)
-- take care of fonts, kerning, ligature, etc
head = nodes.simple_font_handler(head)
-- call tex linebreaking, write to pdf
tex.write(tex.linebreak(head))
-- initize pointers
head = nil
last = nil
end
Based on David Carlisle's comment to my question, I added an adjust node with vertical glue in it. Now the output is as desired. Here's the screenshot and code:
modified linebreak.tex:
documentclass{article}
directlua{require"linebreak.lua"}
begin{document}
raggedright
directlua{
initialize()
addchars('H')
addchars('e')
addchars('l')
addchars('l')
addchars('o')
addchars(' ')
addchars('W')
addchars('o')
addchars('r')
addchars('l')
addchars('d')
addpenalty(1,-10000) % Add line break
vspace(25*65536) % Add vspace
addchars('H')
addchars('e')
addchars('y')
writeparagraph()
}
end{document}
modified linebreak.lua:
local glyph_id = node.id("glyph")
local glue_id = node.id("glue")
local kern_id = node.id("kern")
local penalty_id = node.id("penalty")
local adjust_id = node.id("adjust")
local current_font = font.current()
local font_parameters = font.getfont(current_font).parameters
local n, head, last
function addchars(c)
for s in string.utfvalues(c) do
local char = unicode.utf8.char(s)
if unicode.utf8.match(char,"%s") then
-- its a space
n = node.new(glue_id)
n.width = font_parameters.space
n.shrink = font_parameters.space_shrink
n.stretch = font_parameters.space_stretch
else -- a glyph
n = node.new(glyph_id)
n.font = current_font
n.subtype = 1
n.char = s
n.lang = tex.language
n.uchyph = 1
n.left = tex.lefthyphenmin
n.right = tex.righthyphenmin
end
last.next = n
last = n
end
return last
end
function addpenalty(s,p)
n = node.new(penalty_id)
n.subtype = s or 0
n.penalty = p or 0
last.next = n
last = n
return n
end
function addkern(s,p)
n = node.new(kern_id)
n.subtype = s or 0
n.kern = p or 0
last.next = n
last = n
return n
end
function addadjust(s,h)
n = node.new(adjust_id)
n.subtype = s or 0
n.head = h
last.next = n
last = n
return n
end
function vspace(s)
g1 = node.new(glue_id)
g1.width = s
g1.subtype = 0
addadjust(1,g1)
end
function addglue(s,a,b,c,d,e)
n = node.new(glue_id)
n.subtype = s
n.width = a or 0
n.stretch = b or 0
n.shrink = c or 0
n.stretch_order = d or 0
n.shrink_order = e or 0
last.next = n
last = n
return n
end
function initialize()
-- add parindent glue in the beginning, create head node
head = node.new("glue")
head.width = tex.parindent
last = head
end
function writeparagraph()
-- append a penalty and the parfillskip glue at the end of list
addpenalty(0,10000)
addglue(15,0,tex.parfillskip.stretch,tex.parfillskip.stretch_order)
-- create prev pointers
node.slide(head)
-- hyphenate
lang.hyphenate(head)
-- take care of fonts, kerning, ligature, etc
head = nodes.simple_font_handler(head)
-- call linebreaking
tex.write(tex.linebreak(head))
-- initize pointers
head = nil
last = nil
end
Correct answer by reportaman on January 11, 2021
Get help from others!
Recent Questions
Recent Answers
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP