diff options
Diffstat (limited to 'Master/texmf-dist/tex/context/base/node-tra.lua')
-rw-r--r-- | Master/texmf-dist/tex/context/base/node-tra.lua | 425 |
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 |