summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/context/base/node-tra.lua
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex/context/base/node-tra.lua')
-rw-r--r--Master/texmf-dist/tex/context/base/node-tra.lua425
1 files changed, 320 insertions, 105 deletions
diff --git a/Master/texmf-dist/tex/context/base/node-tra.lua b/Master/texmf-dist/tex/context/base/node-tra.lua
index 5acd70baf2e..38855f65934 100644
--- a/Master/texmf-dist/tex/context/base/node-tra.lua
+++ b/Master/texmf-dist/tex/context/base/node-tra.lua
@@ -11,45 +11,71 @@ if not modules then modules = { } end modules ['node-tra'] = {
might become a runtime module instead. This module will be cleaned up!</p>
--ldx]]--
-local utf = unicode.utf8
-local format, match, concat, rep, utfchar = string.format, string.match, table.concat, string.rep, utf.char
+local utfchar = utf.char
+local concat = table.concat
+local format, match, gmatch, concat, rep = string.format, string.match, string.gmatch, table.concat, string.rep
+local lpegmatch = lpeg.match
+local write_nl = texio.write_nl
-local ctxcatcodes = tex.ctxcatcodes
+local report_nodes = logs.reporter("nodes","tracing")
-fonts = fonts or { }
-fonts.tfm = fonts.tfm or { }
-fonts.ids = fonts.ids or { }
+fonts = fonts or { }
+nodes = nodes or { }
-nodes = nodes or { }
-nodes.tracers = nodes.tracers or { }
-nodes.tracers.characters = nodes.tracers.characters or { }
-nodes.tracers.steppers = nodes.tracers.steppers or { }
+local fonts, nodes, node, context = fonts, nodes, node, context
-local glyph = node.id('glyph')
-local hlist = node.id('hlist')
-local vlist = node.id('vlist')
-local disc = node.id('disc')
-local glue = node.id('glue')
-local kern = node.id('kern')
-local rule = node.id('rule')
-local whatsit = node.id('whatsit')
+nodes.tracers = nodes.tracers or { }
+local tracers = nodes.tracers
+
+nodes.tasks = nodes.tasks or { }
+local tasks = nodes.tasks
+
+nodes.handlers = nodes.handlers or { }
+local handlers = nodes.handlers
+
+nodes.injections = nodes.injections or { }
+local injections = nodes.injections
+
+tracers.characters = tracers.characters or { }
+tracers.steppers = tracers.steppers or { }
+
+local char_tracers = tracers.characters
+local step_tracers = tracers.steppers
local copy_node_list = node.copy_list
local hpack_node_list = node.hpack
local free_node_list = node.flush_list
-local first_character = node.first_character
-local node_type = node.type
local traverse_nodes = node.traverse
-local texsprint = tex.sprint
-local fontdata = fonts.ids
+local nodecodes = nodes.nodecodes
+local whatcodes = nodes.whatcodes
+local skipcodes = nodes.skipcodes
+
+local glyph_code = nodecodes.glyph
+local hlist_code = nodecodes.hlist
+local vlist_code = nodecodes.vlist
+local disc_code = nodecodes.disc
+local glue_code = nodecodes.glue
+local kern_code = nodecodes.kern
+local rule_code = nodecodes.rule
+local whatsit_code = nodecodes.whatsit
+
+local localpar_code = whatcodes.localpar
+local dir_code = whatcodes.dir
+
+local userskip_code = skipcodes.userskip
-function nodes.tracers.characters.collect(head,list,tag,n)
+local nodepool = nodes.pool
+
+local new_glyph = nodepool.glyph
+
+function char_tracers.collect(head,list,tag,n)
+ local fontdata = fonts.hashes.identifiers
n = n or 0
local ok, fn = false, nil
while head do
local id = head.id
- if id == glyph then
+ if id == glyph_code then
local f = head.font
if f ~= fn then
ok, fn = false, f
@@ -64,7 +90,7 @@ function nodes.tracers.characters.collect(head,list,tag,n)
end
local l = list[n][tag]
l[#l+1] = { c, f, i }
- elseif id == disc then
+ elseif id == disc_code then
-- skip
else
ok = false
@@ -73,7 +99,7 @@ function nodes.tracers.characters.collect(head,list,tag,n)
end
end
-function nodes.tracers.characters.equal(ta, tb)
+function char_tracers.equal(ta, tb)
if #ta ~= #tb then
return false
else
@@ -87,7 +113,7 @@ function nodes.tracers.characters.equal(ta, tb)
return true
end
-function nodes.tracers.characters.string(t)
+function char_tracers.string(t)
local tt = { }
for i=1,#t do
tt[i] = utfchar(t[i][1])
@@ -95,7 +121,7 @@ function nodes.tracers.characters.string(t)
return concat(tt,"")
end
-function nodes.tracers.characters.unicodes(t,decimal)
+function char_tracers.unicodes(t,decimal)
local tt = { }
for i=1,#t do
local n = t[i][1]
@@ -110,7 +136,7 @@ function nodes.tracers.characters.unicodes(t,decimal)
return concat(tt," ")
end
-function nodes.tracers.characters.indices(t,decimal)
+function char_tracers.indices(t,decimal)
local tt = { }
for i=1,#t do
local n = t[i][3]
@@ -125,20 +151,20 @@ function nodes.tracers.characters.indices(t,decimal)
return concat(tt," ")
end
-function nodes.tracers.characters.start()
- local npc = nodes.process_characters
+function char_tracers.start()
+ local npc = handlers.characters
local list = { }
- function nodes.process_characters(head)
+ function handlers.characters(head)
local n = #list
- nodes.tracers.characters.collect(head,list,'before',n)
+ char_tracers.collect(head,list,'before',n)
local h, d = npc(head)
- nodes.tracers.characters.collect(head,list,'after',n)
+ char_tracers.collect(head,list,'after',n)
if #list > n then
list[#list+1] = { }
end
return h, d
end
- function nodes.tracers.characters.stop()
+ function char_tracers.stop()
tracers.list['characters'] = list
local variables = {
['title'] = 'ConTeXt Character Processing Information',
@@ -146,7 +172,7 @@ function nodes.tracers.characters.start()
['color-background-two'] = lmx.get('color-background-purple'),
}
lmx.show('context-characters.lmx',variables)
- nodes.process_characters = npc
+ handlers.characters = npc
tasks.restart("processors", "characters")
end
tasks.restart("processors", "characters")
@@ -154,14 +180,14 @@ end
local stack = { }
-function nodes.tracers.start(tag)
+function tracers.start(tag)
stack[#stack+1] = tag
- local tracer = nodes.tracers[tag]
+ local tracer = tracers[tag]
if tracer and tracer.start then
tracer.start()
end
end
-function nodes.tracers.stop()
+function tracers.stop()
local tracer = stack[#stack]
if tracer and tracer.stop then
tracer.stop()
@@ -173,15 +199,15 @@ end
local collection, collecting, messages = { }, false, { }
-function nodes.tracers.steppers.start()
+function step_tracers.start()
collecting = true
end
-function nodes.tracers.steppers.stop()
+function step_tracers.stop()
collecting = false
end
-function nodes.tracers.steppers.reset()
+function step_tracers.reset()
for i=1,#collection do
local c = collection[i]
if c then
@@ -191,23 +217,23 @@ function nodes.tracers.steppers.reset()
collection, messages = { }, { }
end
-function nodes.tracers.steppers.nofsteps()
+function step_tracers.nofsteps()
return tex.write(#collection)
end
-function nodes.tracers.steppers.glyphs(n,i)
+function step_tracers.glyphs(n,i)
local c = collection[i]
if c then
tex.box[n] = hpack_node_list(copy_node_list(c))
end
end
-function nodes.tracers.steppers.features()
--- local f = first_character(collection[1])
--- if f then -- something fishy with first_character
+function step_tracers.features()
+ -- we cannot use first_glyph here as it only finds characters with subtype < 256
+ local fontdata = fonts.hashes.identifiers
local f = collection[1]
while f do
- if f.id == glyph then
+ if f.id == glyph_code then
local tfmdata, t = fontdata[f.font], { }
for feature, value in table.sortedhash(tfmdata.shared.features) do
if feature == "number" or feature == "features" then
@@ -223,9 +249,9 @@ function nodes.tracers.steppers.features()
end
end
if #t > 0 then
- texsprint(ctxcatcodes,concat(t,", "))
+ context(concat(t,", "))
else
- texsprint(ctxcatcodes,"no features")
+ context("no features")
end
return
end
@@ -233,41 +259,48 @@ function nodes.tracers.steppers.features()
end
end
-function nodes.tracers.fontchar(font,char)
- local n = nodes.glyph()
+function tracers.fontchar(font,char)
+ local fontchar = fonts.hashes.characters
+ local n = new_glyph()
n.font, n.char, n.subtype = font, char, 256
- node.write(n)
+ context(n)
end
-function nodes.tracers.steppers.codes(i,command)
+function step_tracers.codes(i,command)
+ local fontdata = fonts.hashes.identifiers
local c = collection[i]
while c do
local id = c.id
- if id == glyph then
+ if id == glyph_code then
if command then
- texsprint(ctxcatcodes,format("%s{%s}{%s}",command,c.font,c.char))
+ local f, c = c.font,c.char
+ local d = fontdata[f].descriptions
+ local d = d and d[c]
+ context[command](f,c,d and d.class or "")
else
- texsprint(ctxcatcodes,format("[%s:U+%04X]",c.font,c.char))
+ context("[%s:U+%04X]",c.font,c.char)
end
- elseif id == whatsit and (c.subtype == 6 or c.subtype == 7) then
- texsprint(ctxcatcodes,format("[%s]",c.dir))
+ elseif id == whatsit_code and (c.subtype == localpar_code or c.subtype == dir_code) then
+ context("[%s]",c.dir)
else
- texsprint(ctxcatcodes,format("[%s]",node_type(id)))
+ context("[%s]",nodecodes[id])
end
c = c.next
end
end
-function nodes.tracers.steppers.messages(i,command,split)
+function step_tracers.messages(i,command,split)
local list = messages[i] -- or { "no messages" }
if list then
for i=1,#list do
local l = list[i]
- if split then
+ if not command then
+ context("(%s)",l)
+ elseif split then
local a, b = match(l,"^(.-)%s*:%s*(.*)$")
- texsprint(ctxcatcodes,format("%s{%s}{%s}",command,a or l,b or ""))
+ context[command](a or l or "",b or "")
else
- texsprint(ctxcatcodes,format("%s{%s}",command,l))
+ context[command](l)
end
end
end
@@ -275,29 +308,29 @@ end
-- hooks into the node list processor (see otf)
-function nodes.tracers.steppers.check(head)
+function step_tracers.check(head)
if collecting then
- nodes.tracers.steppers.reset()
+ step_tracers.reset()
local n = copy_node_list(head)
- nodes.inject_kerns(n,nil,"trace",true)
- nodes.protect_glyphs(n) -- can be option
+ injections.handler(n,nil,"trace",true)
+ handlers.protectglyphs(n) -- can be option
collection[1] = n
end
end
-function nodes.tracers.steppers.register(head)
+function step_tracers.register(head)
if collecting then
local nc = #collection+1
if messages[nc] then
local n = copy_node_list(head)
- nodes.inject_kerns(n,nil,"trace",true)
- nodes.protect_glyphs(n) -- can be option
+ injections.handler(n,nil,"trace",true)
+ handlers.protectglyphs(n) -- can be option
collection[nc] = n
end
end
end
-function nodes.tracers.steppers.message(str,...)
+function step_tracers.message(str,...)
str = format(str,...)
if collecting then
local n = #collection + 1
@@ -310,55 +343,72 @@ end
-- this will be reorganized:
-function nodes.show_list(head, message)
+function nodes.showlist(head, message)
if message then
- texio.write_nl(message)
+ write_nl(message)
end
for n in traverse_nodes(head) do
- texio.write_nl(tostring(n))
+ write_nl(tostring(n))
end
end
-function nodes.check_glyphs(head,message)
+function nodes.handlers.checkglyphs(head,message)
local t = { }
- for g in traverse_id(glyph,head) do
+ for g in traverse_id(glyph_code,head) do
t[#t+1] = format("U+%04X:%s",g.char,g.subtype)
end
if #t > 0 then
- logs.report(message or "nodes","%s glyphs: %s",#t,concat(t," "))
+ if message and message ~= "" then
+ report_nodes("%s, %s glyphs: %s",message,#t,concat(t," "))
+ else
+ report_nodes("%s glyphs: %s",#t,concat(t," "))
+ end
end
return false
end
-function nodes.tosequence(start,stop,compact)
+function nodes.handlers.checkforleaks(sparse)
+ local l = { }
+ local q = node.usedlist()
+ for p in traverse(q) do
+ local s = table.serialize(nodes.astable(p,sparse),nodecodes[p.id])
+ l[s] = (l[s] or 0) + 1
+ end
+ node.flush_list(q)
+ for k, v in next, l do
+ write_nl(format("%s * %s", v, k))
+ end
+end
+
+local function tosequence(start,stop,compact)
if start then
local t = { }
while start do
local id = start.id
- if id == glyph then
+ if id == glyph_code then
local c = start.char
if compact then
if start.components then
- t[#t+1] = nodes.tosequence(start.components,nil,compact)
+ t[#t+1] = tosequence(start.components,nil,compact)
else
- t[#t+1] = format("%s",utfchar(c))
+ t[#t+1] = utfchar(c)
end
else
t[#t+1] = format("U+%04X:%s",c,utfchar(c))
end
- elseif id == whatsit and start.subtype == 6 or start.subtype == 7 then
+ elseif id == whatsit_code and start.subtype == localpar_code or start.subtype == dir_code then
t[#t+1] = "[" .. start.dir .. "]"
- elseif id == rule then
+ elseif id == rule_code then
if compact then
t[#t+1] = "|"
else
- t[#t+1] = node_type(id)
+ t[#t+1] = nodecodes[id]
end
else
if compact then
t[#t+1] = "[]"
else
- t[#t+1] = node_type(id)
+ t[#t+1] = nodecodes[id]
end
end
if start == stop then
@@ -377,23 +427,25 @@ function nodes.tosequence(start,stop,compact)
end
end
+nodes.tosequence = tosequence
+
function nodes.report(t,done)
if done then
if status.output_active then
- logs.report("nodes","output, changed, %s nodes",nodes.count(t))
+ report_nodes("output, changed, %s nodes",nodes.count(t))
else
- texio.write("nodes","normal, changed, %s nodes",nodes.count(t))
+ write_nl("nodes","normal, changed, %s nodes",nodes.count(t))
end
else
if status.output_active then
- logs.report("nodes","output, unchanged, %s nodes",nodes.count(t))
+ report_nodes("output, unchanged, %s nodes",nodes.count(t))
else
- texio.write("nodes","normal, unchanged, %s nodes",nodes.count(t))
+ write_nl("nodes","normal, unchanged, %s nodes",nodes.count(t))
end
end
end
-function nodes.pack_list(head)
+function nodes.packlist(head)
local t = { }
for n in traverse(head) do
t[#t+1] = tostring(n)
@@ -401,7 +453,7 @@ function nodes.pack_list(head)
return t
end
-function nodes.ids_to_string(head,tail)
+function nodes.idstostring(head,tail)
local t, last_id, last_n = { }, nil, 0
for n in traverse_nodes(head,tail) do -- hm, does not stop at tail
local id = n.id
@@ -411,9 +463,9 @@ function nodes.ids_to_string(head,tail)
last_n = last_n + 1
else
if last_n > 1 then
- t[#t+1] = format("[%s*%s]",last_n,node_type(last_id) or "?")
+ t[#t+1] = format("[%s*%s]",last_n,nodecodes[last_id] or "?")
else
- t[#t+1] = format("[%s]",node_type(last_id) or "?")
+ t[#t+1] = format("[%s]",nodecodes[last_id] or "?")
end
last_id, last_n = id, 1
end
@@ -424,22 +476,55 @@ function nodes.ids_to_string(head,tail)
if not last_id then
t[#t+1] = "no nodes"
elseif last_n > 1 then
- t[#t+1] = format("[%s*%s]",last_n,node_type(last_id) or "?")
+ t[#t+1] = format("[%s*%s]",last_n,nodecodes[last_id] or "?")
else
- t[#t+1] = format("[%s]",node_type(last_id) or "?")
+ t[#t+1] = format("[%s]",nodecodes[last_id] or "?")
end
return concat(t," ")
end
-nodes.ids_tostring = nodes.ids_to_string
-
-local function show_simple_list(h,depth,n)
+--~ function nodes.xidstostring(head,tail) -- only for special tracing of backlinks
+--~ local n = head
+--~ while n.next do
+--~ n = n.next
+--~ end
+--~ local t, last_id, last_n = { }, nil, 0
+--~ while n do
+--~ local id = n.id
+--~ if not last_id then
+--~ last_id, last_n = id, 1
+--~ elseif last_id == id then
+--~ last_n = last_n + 1
+--~ else
+--~ if last_n > 1 then
+--~ t[#t+1] = format("[%s*%s]",last_n,nodecodes[last_id] or "?")
+--~ else
+--~ t[#t+1] = format("[%s]",nodecodes[last_id] or "?")
+--~ end
+--~ last_id, last_n = id, 1
+--~ end
+--~ if n == head then
+--~ break
+--~ end
+--~ n = n.prev
+--~ end
+--~ if not last_id then
+--~ t[#t+1] = "no nodes"
+--~ elseif last_n > 1 then
+--~ t[#t+1] = format("[%s*%s]",last_n,nodecodes[last_id] or "?")
+--~ else
+--~ t[#t+1] = format("[%s]",nodecodes[last_id] or "?")
+--~ end
+--~ return table.concat(table.reversed(t)," ")
+--~ end
+
+local function showsimplelist(h,depth,n)
while h do
- texio.write_nl(rep(" ",n) .. tostring(h))
+ write_nl(rep(" ",n) .. tostring(h))
if not depth or n < depth then
local id = h.id
- if id == hlist or id == vlist then
- show_simple_list(h.list,depth,n+1)
+ if id == hlist_code or id == vlist_code then
+ showsimplelist(h.list,depth,n+1)
end
end
h = h.next
@@ -454,13 +539,13 @@ end
--~ callback.register('buildpage_filter',nil)
--~ \stopluacode
-nodes.show_simple_list = function(h,depth) show_simple_list(h,depth,0) end
+nodes.showsimplelist = function(h,depth) showsimplelist(h,depth,0) end
-function nodes.list_to_utf(h,joiner)
+function nodes.listtoutf(h,joiner)
local joiner = (joiner ==true and utfchar(0x200C)) or joiner -- zwnj
local w = { }
while h do
- if h.id == glyph then -- always true
+ if h.id == glyph_code then -- always true
w[#w+1] = utfchar(h.char)
if joiner then
w[#w+1] = joiner
@@ -472,3 +557,133 @@ function nodes.list_to_utf(h,joiner)
end
return concat(w)
end
+
+local what = { [0] = "unknown", "line", "box", "indent", "row", "cell" }
+
+local function showboxes(n,symbol,depth)
+ depth, symbol = depth or 0, symbol or "."
+ for n in traverse_nodes(n) do
+ local id = n.id
+ if id == hlist_code or id == vlist_code then
+ local s = n.subtype
+ report_nodes(rep(symbol,depth) .. what[s] or s)
+ showboxes(n.list,symbol,depth+1)
+ end
+ end
+end
+
+nodes.showboxes = showboxes
+
+local threshold = 65536
+
+local function toutf(list,result,nofresult,stopcriterium)
+ if list then
+ local fontchar = fonts.hashes.characters
+ for n in traverse_nodes(list) do
+ local id = n.id
+ if id == glyph_code then
+ local components = n.components
+ if components then
+ result, nofresult = toutf(components,result,nofresult)
+ else
+ local c = n.char
+ local fc = fontchar[n.font]
+ if fc then
+ local u = fc[c].tounicode
+ if u then
+ for s in gmatch(u,"....") do
+ nofresult = nofresult + 1
+ result[nofresult] = utfchar(tonumber(s,16))
+ end
+ else
+ nofresult = nofresult + 1
+ result[nofresult] = utfchar(c)
+ end
+ else
+ nofresult = nofresult + 1
+ result[nofresult] = utfchar(c)
+ end
+ end
+ elseif id == disc_code then
+ result, nofresult = toutf(n.replace,result,nofresult) -- needed?
+ elseif id == hlist_code or id == vlist_code then
+--~ if nofresult > 0 and result[nofresult] ~= " " then
+--~ nofresult = nofresult + 1
+--~ result[nofresult] = " "
+--~ end
+ result, nofresult = toutf(n.list,result,nofresult)
+ elseif id == glue_code and n.subtype == userskip_code and n.spec.width > threshold then
+ if nofresult > 0 and result[nofresult] ~= " " then
+ nofresult = nofresult + 1
+ result[nofresult] = " "
+ end
+ elseif id == kern_code and n.kern > threshold then
+ if nofresult > 0 and result[nofresult] ~= " " then
+ nofresult = nofresult + 1
+ result[nofresult] = " "
+ end
+ end
+ if n == stopcriterium then
+ break
+ end
+ end
+ end
+ return result, nofresult
+end
+
+function nodes.toutf(list,stopcriterium)
+ local result, nofresult = toutf(list,{},0,stopcriterium)
+ return concat(result)
+end
+
+-- might move elsewhere
+
+local ptfactor = number.dimenfactors.pt
+local bpfactor = number.dimenfactors.bp
+local stripper = lpeg.patterns.stripzeros
+
+local points = function(n)
+ return lpegmatch(stripper,format("%.5fpt",n*ptfactor))
+end
+
+local basepoints = function(n)
+ return lpegmatch(stripper,format("%.5fbp",n*bpfactor))
+end
+
+number.points = points
+number.basepoints = basepoints
+
+--~ function nodes.thespec(s)
+--~ local stretch_order = s.stretch_order
+--~ local shrink_order = s.shrink_order
+--~ local stretch_unit = (stretch_order ~= 0) and ("fi".. string.rep("l",stretch_order)) or "sp"
+--~ local shrink_unit = (shrink_order ~= 0) and ("fi".. string.rep("l",shrink_order)) or "sp"
+--~ return string.format("%ssp+ %ssp - %ssp",s.width,s.stretch,stretch_unit,s.shrink,shrink_unit)
+--~ end
+
+local colors = { }
+tracers.colors = colors
+
+local get_attribute = node.has_attribute
+local set_attribute = node.set_attribute
+local unset_attribute = node.unset_attribute
+
+local attribute = attributes.private('color')
+local colormodel = attributes.private('colormodel')
+local mapping = attributes.list[attribute] or { }
+
+function colors.set(n,c,s)
+ local mc = mapping[c]
+ if not mc then
+ unset_attribute(n,attribute)
+ else
+ if not get_attribute(n,colormodel) then
+ set_attribute(n,colormodel,s or 1)
+ end
+ set_attribute(n,attribute,mc)
+ end
+end
+
+function colors.reset(n)
+ unset_attribute(n,attribute)
+end