summaryrefslogtreecommitdiff
path: root/tex/context/base/node-ini.lua
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/node-ini.lua')
-rw-r--r--tex/context/base/node-ini.lua578
1 files changed, 306 insertions, 272 deletions
diff --git a/tex/context/base/node-ini.lua b/tex/context/base/node-ini.lua
index 77835e04b..4ef9e05eb 100644
--- a/tex/context/base/node-ini.lua
+++ b/tex/context/base/node-ini.lua
@@ -11,8 +11,8 @@ if not modules then modules = { } end modules ['node-ini'] = {
implement a few helper functions.</p>
--ldx]]--
-nodes = nodes or { }
-nodes.trace = false
+nodes = nodes or { }
+nodes.trace = false
-- handy helpers
@@ -59,7 +59,7 @@ nodes.processors.char = { }
nodes.processors.char.proc = { }
function nodes.report(t,done)
- if nodes.trace then
+ if nodes.trace then -- best also test this before calling
if done then
if status.output_active then
texio.write(string.format("<++ %s>",nodes.count(t)))
@@ -296,6 +296,309 @@ if not fonts then fonts = { } end
if not fonts.tfm then fonts.tfm = { } end
if not fonts.tfm.id then fonts.tfm.id = { } end
+do
+
+ local glyph, hlist, vlist = node.id('glyph'), node.id('hlist'), node.id('vlist')
+ local pushmarks = false
+
+ function nodes.process_glyphs(head)
+ if status.output_active then -- not ok, we need a generic blocker, pagebody ! / attr tex.attibutes
+ -- 25% calls
+ return true
+ elseif not head then
+ -- 25% calls
+ return true
+ elseif not head.next and (head.id == hlist or head.id == vlist) then
+ return head
+ else
+ -- either next or not, but definitely no already processed list
+ input.start_timing(nodes)
+ local usedfonts, found, fontdata, done = { }, false, fonts.tfm.id, false
+ for n in node.traverse_id(glyph,head) do
+ local font = n.font
+ if not usedfonts[font] then
+ local shared = fontdata[font].shared
+ if shared and shared.processors then
+ usedfonts[font], found = shared.processors, true
+ end
+ end
+ end
+ if found then
+ local tail = head
+ if head.next then
+ tail = node.slide(head)
+ else
+ head.prev = nil
+ end
+ for font, processors in pairs(usedfonts) do
+ if pushmarks then
+ local h, d = fonts.pushmarks(head,font)
+ head, done = head or h, done or d
+ end
+ for _, processor in ipairs(processors) do
+ local h, d = processor(head,font)
+ head, done = head or h, done or d
+ end
+ if pushmarks then
+ local h, d = fonts.popmarks(head,font)
+ head, done = head or h, done or d
+ end
+ end
+ end
+ input.stop_timing(nodes)
+ if nodes.trace then
+ nodes.report(head,done)
+ end
+ if done then
+ return head -- something changed
+ elseif head then
+ return true -- nothing changed
+ else
+ return false -- delete list
+ end
+ end
+ end
+
+end
+
+-- vbox: grouptype: vbox vtop output split_off split_keep | box_type: exactly|aditional
+-- hbox: grouptype: hbox adjusted_hbox(=hbox_in_vmode) | box_type: exactly|aditional
+
+do
+
+ local contains, set, attribute = node.has_attribute, node.set_attribute, tex.attribute
+
+ function nodes.inherit_attributes(n)
+ if n then
+ local i = 1
+ while true do
+ local a = attribute[i]
+ if a < 0 then
+ break
+ else
+ local ai = contains(n,i)
+ if not ai then
+ set(n,i,a)
+ end
+ i = i + 1
+ end
+ end
+ end
+ end
+
+end
+
+callback.register('pre_linebreak_filter', nodes.process_glyphs)
+callback.register('hpack_filter', nodes.process_glyphs)
+
+--~ callback.register('pre_linebreak_filter', function(t,...)
+--~ print("pre_linebreak_filter",...)
+--~ return nodes.process_glyphs(t)
+--~ end )
+--~ callback.register('hpack_filter', function(t,...)
+--~ print("hpack_filter",...)
+--~ return nodes.process_glyphs(t)
+--~ end )
+
+function nodes.length(head)
+ if head then
+ local m = 0
+ for n in node.traverse(head) do
+ m = m + 1
+ end
+ return m
+ else
+ return 0
+ end
+end
+
+do
+
+--~ function nodes.totable(n)
+--~ local function totable(n)
+--~ local f, tt = node.fields(n.id,n.subtype), { }
+--~ for _,v in ipairs(f) do
+--~ local nv = n[v]
+--~ if nv then
+--~ local tnv = type(nv)
+--~ if tnv == "string" or tnv == "number" then
+--~ tt[v] = nv
+--~ else -- userdata
+--~ tt[v] = nodes.totable(nv)
+--~ end
+--~ end
+--~ end
+--~ return tt
+--~ end
+--~ local t = { }
+--~ while n do
+--~ t[#t+1] = totable(n)
+--~ n = n.next
+--~ end
+--~ return t
+--~ end
+
+ local expand = {
+ list = true,
+ pre = true,
+ post = true,
+ spec = true,
+ attr = true,
+ components = true,
+ }
+
+ -- flat: don't use next, but indexes
+ -- verbose: also add type
+
+ function nodes.totable(n,flat,verbose)
+ local function totable(n,verbose)
+ local f = node.fields(n.id,n.subtype)
+ local tt = { }
+ for _,v in ipairs(f) do
+ if n[v] then
+ if v == "ref_count" then
+ -- skip
+ elseif expand[v] then -- or: type(n[v]) ~= "string" or type(n[v]) ~= "number"
+ tt[v] = nodes.totable(n[v],flat,verbose)
+ else
+ tt[v] = n[v]
+ end
+ end
+ end
+ if verbose then
+ tt.type = node.type(tt.id)
+ end
+ return tt
+ end
+ if n then
+ if flat then
+ local t = { }
+ while n do
+ t[#t+1] = totable(n,verbose)
+ n = n.next
+ end
+ return t
+ else
+ local t = totable(n,verbose)
+ if n.next then
+ t.next = nodes.totable(n.next,flat,verbose)
+ end
+ return t
+ end
+ else
+ return { }
+ end
+ end
+
+ local function key(k)
+ if type(k) == "number" then
+ return "["..k.."]"
+ else
+ return k
+ end
+ end
+
+ local function serialize(root,name,handle,depth,m)
+ handle = handle or print
+ if depth then
+ depth = depth .. " "
+ handle(("%s%s={"):format(depth,key(name)))
+ else
+ depth = ""
+ if type(name) == "string" then
+ if name == "return" then
+ handle("return {")
+ else
+ handle(name .. "={")
+ end
+ elseif type(name) == "number" then
+ handle("[" .. name .. "]={")
+ else
+ handle("t={")
+ end
+ end
+ if root then
+ local fld
+ if root.id then
+ fld = node.fields(root.id,root.subtype)
+ else
+ fld = table.sortedkeys(root)
+ end
+ if type(root) == 'table' and root['type'] then -- userdata or table
+ handle(("%s %s=%q,"):format(depth,'type',root['type']))
+ end
+ for _,k in ipairs(fld) do
+ if k then
+ local v = root[k]
+ local t = type(v)
+ if t == "number" then
+ handle(("%s %s=%s,"):format(depth,key(k),v))
+ elseif t == "string" then
+ handle(("%s %s=%q,"):format(depth,key(k),v))
+ elseif v then -- userdata or table
+ serialize(v,k,handle,depth,m+1)
+ end
+ end
+ end
+ if root['next'] then -- userdata or table
+ serialize(root['next'],'next',handle,depth,m+1)
+ end
+ end
+ if m and m > 0 then
+ handle(("%s},"):format(depth))
+ else
+ handle(("%s}"):format(depth))
+ end
+ end
+
+ function nodes.serialize(root,name)
+ local t = { }
+ local function flush(s)
+ t[#t+1] = s
+ end
+ serialize(root, name, flush, nil, 0)
+ return table.concat(t,"\n")
+ end
+
+ function nodes.serializebox(n,flat,verbose)
+ return nodes.serialize(nodes.totable(tex.box[n],flat,verbose))
+ -- return nodes.serialize(tex.box[n])
+ end
+
+ function nodes.visualizebox(...)
+ -- tex.sprint(tex.ctxcatcodes,"\\starttyping\n" .. nodes.serializebox(...) .. "\n\\stoptyping\n")
+ tex.print(tex.ctxcatcodes,"\\starttyping")
+ tex.print(nodes.serializebox(...))
+ tex.print("\\stoptyping")
+ end
+
+end
+
+if not node.list_has_attribute then
+
+ function node.list_has_attribute(list,attribute)
+ if list and attribute then
+ for n in node.traverse(list) do
+ local a = has_attribute(n,attribute)
+ if a then return a end
+ end
+ end
+ return false
+ end
+
+end
+
+function nodes.pack_list(head)
+ local t = { }
+ for n in node.traverse(head) do
+ t[#t+1] = tostring(n)
+ end
+ return t
+end
+
+-- old code
+
+
--~ function nodes.do_process_glyphs(stack)
--~ if not stack or #stack == 0 then
--~ return false
@@ -634,272 +937,3 @@ if not fonts.tfm.id then fonts.tfm.id = { } end
--~ end
--~ end
-
-do
-
- local glyph = node.id('glyph')
- local pushmarks = false
-
- function do_process_glyphs(head) -- beware, we need to handle shifted heads -- todo
- if not head then
- return head
- end
- local usedfonts, found, fontdata = { }, false, fonts.tfm.id
- for n in node.traverse_id(glyph,head) do
- local font = n.font
- if not usedfonts[font] then
- local shared = fontdata[font].shared
- if shared and shared.processors then
- usedfonts[font], found = shared.processors, true
- end
- end
- end
- if not found then
- return head, false
- else
- local tail, done = node.slide(head), false
- for font, processors in pairs(usedfonts) do
- if pushmarks then
- local h, d = fonts.pushmarks(head,font)
- head, done = head or h, done or d
- end
- for _, processor in ipairs(processors) do
- local h, d = processor(head,font)
- head, done = head or h, done or d
- end
- if pushmarks then
- local h, d = fonts.popmarks(head,font)
- head, done = head or h, done or d
- end
- end
- return head, done
- end
- end
-
- function nodes.process_glyphs(head)
- if status.output_active then -- not ok, we need a generic blocker, pagebody ! / attr tex.attibutes
- return true
- else
- input.start_timing(nodes)
- local head, done = do_process_glyphs(head)
- input.stop_timing(nodes)
- nodes.report(head,done)
- if done then
- return head -- something changed
- elseif head then
- return true -- nothing changed
- else
- return false -- delete list
- end
- end
- end
-
-end
-
--- vbox: grouptype: vbox vtop output split_off split_keep | box_type: exactly|aditional
--- hbox: grouptype: hbox adjusted_hbox(=hbox_in_vmode) | box_type: exactly|aditional
-
-callback.register('pre_linebreak_filter', nodes.process_glyphs)
-callback.register('hpack_filter', nodes.process_glyphs)
-
---~ callback.register('pre_linebreak_filter', function(t,...)
---~ print("pre_linebreak_filter",...)
---~ return nodes.process_glyphs(t)
---~ end )
---~ callback.register('hpack_filter', function(t,...)
---~ print("hpack_filter",...)
---~ return nodes.process_glyphs(t)
---~ end )
-
-function nodes.length(head)
- if head then
- local m = 0
- for n in node.traverse(head) do
- m = m + 1
- end
- return m
- else
- return 0
- end
-end
-
-do
-
---~ function nodes.totable(n)
---~ function totable(n)
---~ local f, tt = node.fields(n.id,n.subtype), { }
---~ for _,v in ipairs(f) do
---~ local nv = n[v]
---~ if nv then
---~ local tnv = type(nv)
---~ if tnv == "string" or tnv == "number" then
---~ tt[v] = nv
---~ else -- userdata
---~ tt[v] = nodes.totable(nv)
---~ end
---~ end
---~ end
---~ return tt
---~ end
---~ local t = { }
---~ while n do
---~ t[#t+1] = totable(n)
---~ n = n.next
---~ end
---~ return t
---~ end
-
- local expand = {
- list = true,
- pre = true,
- post = true,
- spec = true,
- attr = true,
- components = true,
- }
-
- -- flat: don't use next, but indexes
- -- verbose: also add type
-
- function nodes.totable(n,flat,verbose)
- function totable(n,verbose)
- local f = node.fields(n.id,n.subtype)
- local tt = { }
- for _,v in ipairs(f) do
- if n[v] then
- if v == "ref_count" then
- -- skip
- elseif expand[v] then -- or: type(n[v]) ~= "string" or type(n[v]) ~= "number"
- tt[v] = nodes.totable(n[v],flat,verbose)
- else
- tt[v] = n[v]
- end
- end
- end
- if verbose then
- tt.type = node.type(tt.id)
- end
- return tt
- end
- if flat then
- local t = { }
- while n do
- t[#t+1] = totable(n,verbose)
- n = n.next
- end
- return t
- else
- local t = totable(n,verbose)
- if n.next then
- t.next = nodes.totable(n.next,flat,verbose)
- end
- return t
- end
- end
-
- local function key(k)
- if type(k) == "number" then
- return "["..k.."]"
- else
- return k
- end
- end
-
- local function serialize(root,name,handle,depth,m)
- handle = handle or print
- if depth then
- depth = depth .. " "
- handle(("%s%s={"):format(depth,key(name)))
- else
- depth = ""
- if type(name) == "string" then
- if name == "return" then
- handle("return {")
- else
- handle(name .. "={")
- end
- elseif type(name) == "number" then
- handle("[" .. name .. "]={")
- else
- handle("t={")
- end
- end
- if root then
- local fld
- if root.id then
- fld = node.fields(root.id,root.subtype)
- else
- fld = table.sortedkeys(root)
- end
- if type(root) == 'table' and root['type'] then -- userdata or table
- handle(("%s %s=%q,"):format(depth,'type',root['type']))
- end
- for _,k in ipairs(fld) do
- if k then
- local v = root[k]
- local t = type(v)
- if t == "number" then
- handle(("%s %s=%s,"):format(depth,key(k),v))
- elseif t == "string" then
- handle(("%s %s=%q,"):format(depth,key(k),v))
- elseif v then -- userdata or table
- serialize(v,k,handle,depth,n+1)
- end
- end
- end
- if root['next'] then -- userdata or table
- serialize(root['next'],'next',handle,depth,n+1)
- end
- end
- if m and m > 0 then
- handle(("%s},"):format(depth))
- else
- handle(("%s}"):format(depth))
- end
- end
-
- function nodes.serialize(root,name)
- local t = { }
- local function flush(s)
- t[#t+1] = s
- end
- serialize(root, name, flush, nil, nil)
- return table.concat(t,"\n")
- end
-
- function nodes.serializebox(n,flat,verbose)
- return nodes.serialize(nodes.totable(tex.box[n],flat,verbose))
- -- return nodes.serialize(tex.box[n])
- end
-
- function nodes.visualizebox(...)
- -- tex.sprint(tex.ctxcatcodes,"\\starttyping\n" .. nodes.serializebox(...) .. "\n\\stoptyping\n")
- tex.print(tex.ctxcatcodes,"\\starttyping")
- tex.print(nodes.serializebox(...))
- tex.print("\\stoptyping")
- end
-
-end
-
-if not node.list_has_attribute then
-
- function node.list_has_attribute(list,attribute)
- if list and attribute then
- for n in node.traverse(list) do
- local a = has_attribute(n,attribute)
- if a then return a end
- end
- end
- return false
- end
-
-end
-
-function nodes.pack_list(head)
- local t = { }
- for n in node.traverse(head) do
- t[#t+1] = tostring(n)
- end
- return t
-end
-