TransWikia.com

LuaTeX node library: Vertical glue/kern does not work in manually made nodelist, what is missing?

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 a local variable name clash with another lua file that I load with require, for instance variable local head? 2) Instead of making the functions global, is there a way to call them with something like linebreak. 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):
Screenshot of output

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

One Answer

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:

Screenshot showing the output of modified 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

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP