summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/context/base/node-ini.lua
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex/context/base/node-ini.lua')
-rw-r--r--Master/texmf-dist/tex/context/base/node-ini.lua1088
1 files changed, 139 insertions, 949 deletions
diff --git a/Master/texmf-dist/tex/context/base/node-ini.lua b/Master/texmf-dist/tex/context/base/node-ini.lua
index 5923a49e40b..3ff73c62f16 100644
--- a/Master/texmf-dist/tex/context/base/node-ini.lua
+++ b/Master/texmf-dist/tex/context/base/node-ini.lua
@@ -7,234 +7,68 @@ if not modules then modules = { } end modules ['node-ini'] = {
}
--[[ldx--
-<p>Access to nodes is what gives <l n='luatex'/> its power. Here we
-implement a few helper functions. These functions are rather optimized.</p>
+<p>Most of the code that had accumulated here is now separated in
+modules.</p>
--ldx]]--
-nodes = nodes or { }
-nodes.trace = false
-nodes.ignore = nodes.ignore or false
-
--- handy helpers
-
-if node.protect_glyphs then
-
- nodes.protect_glyphs = node.protect_glyphs
- nodes.unprotect_glyphs = node.unprotect_glyphs
-
-else do
-
- -- initial value subtype : X000 0001 = 1 = 0x01 = char
- --
- -- expected before linebreak : X000 0000 = 0 = 0x00 = glyph
- -- X000 0010 = 2 = 0x02 = ligature
- -- X000 0100 = 4 = 0x04 = ghost
- -- X000 1010 = 10 = 0x0A = leftboundary lig
- -- X001 0010 = 18 = 0x12 = rightboundary lig
- -- X001 1010 = 26 = 0x1A = both boundaries lig
- -- X000 1100 = 12 = 0x1C = leftghost
- -- X001 0100 = 20 = 0x14 = rightghost
-
+-- this module is being reconstructed
- local glyph = node.id('glyph')
- local traverse_id = node.traverse_id
+local utf = unicode.utf8
+local next, type = next, type
+local format, concat, match, utfchar = string.format, table.concat, string.match, utf.char
- function nodes.protect_glyphs(head)
- local done = false
- for g in traverse_id(glyph,head) do
- local s = g.subtype
- if s == 1 then
- done, g.subtype = true, 256
- elseif s <= 256 then
- done, g.subtype = true, 256 + s
- end
- end
- return done
- end
-
- function nodes.unprotect_glyphs(head)
- local done = false
- for g in traverse_id(glyph,head) do
- local s = g.subtype
- if s > 256 then
- done, g.subtype = true, s - 256
- end
- end
- return done
- end
+local chardata = characters and characters.data
-end end
-
-do
-
- local remove, free = node.remove, node.free
-
- --~ function nodes.remove(head, current, free_too)
- --~ if head == current then
- --~ local cn = current.next
- --~ if cn then
- --~ cn.prev = nil
- --~ if free_too then
- --~ node.free(current)
- --~ return cn, cn, nil
- --~ else
- --~ current.prev = nil
- --~ current.next = nil
- --~ return cn, cn, current
- --~ end
- --~ else
- --~ if free_too then
- --~ node.free(current)
- --~ return nil, nil, nil
- --~ else
- --~ return head,current,current
- --~ end
- --~ end
- --~ else
- --~ local cp = current.prev
- --~ local cn = current.next
- --~ if not cp and head.next == current then
- --~ cp = head
- --~ end
- --~ if cn then
- --~ cn.prev = cp
- --~ if cp then
- --~ cp.next = cn
- --~ end
- --~ elseif cp then
- --~ cp.next = nil
- --~ end
- --~ if free_too then
- --~ node.free(current)
- --~ return head, cn, nil
- --~ else
- --~ current.prev = nil
- --~ current.next = nil
- --~ return head, cn, current
- --~ end
- --~ end
- --~ end
-
- function nodes.remove(head, current, free_too)
- local t = current
- head, current = remove(head,current)
- if t then
- if free_too then
- free(t)
- t = nil
- else
- t.next, t.prev = nil, nil
- end
- end
- return head, current, t
- end
+--[[ldx--
+<p>We start with a registration system for atributes so that we can use the
+symbolic names later on.</p>
+--ldx]]--
- function nodes.delete(head,current)
- return nodes.remove(head,current,true)
- end
+attributes = attributes or { }
- nodes.before = node.insert_before -- broken
- nodes.after = node.insert_after
+attributes.names = attributes.names or { }
+attributes.numbers = attributes.numbers or { }
+attributes.list = attributes.list or { }
+attributes.unsetvalue = -0x7FFFFFFF
- function nodes.before(h,c,n)
- if c then
- if c == h then
- n.next = h
- n.prev = nil
- h.prev = n
- else
- local cp = c.prev
- n.next = c
- n.prev = cp
- if cp then
- cp.next = n
- end
- c.prev = n
- return h, n
- end
- end
- return n, n
- end
+storage.register("attributes/names", attributes.names, "attributes.names")
+storage.register("attributes/numbers", attributes.numbers, "attributes.numbers")
+storage.register("attributes/list", attributes.list, "attributes.list")
- function nodes.after(h,c,n)
- if c then
- local cn = c.next
- if cn then
- n.next = cn
- cn.prev = n
- else
- n.next = nil
- end
- c.next = n
- n.prev = c
- if c ~= h then
- return h, n
- end
- end
- return n, n
- end
+local names, numbers, list = attributes.names, attributes.numbers, attributes.list
- function nodes.show_list(head, message)
- if message then
- texio.write_nl(message)
- end
- for n in node.traverse(head) do
- texio.write_nl(tostring(n))
- end
+function attributes.define(name,number) -- at the tex end
+ if not numbers[name] then
+ numbers[name], names[number], list[number] = number, name, { }
end
-
end
--- will move
+--[[ldx--
+<p>We can use the attributes in the range 127-255 (outside user space). These
+are only used when no attribute is set at the \TEX\ end which normally
+happens in <l n='context'/>.</p>
+--ldx]]--
-nodes.processors = { }
-nodes.processors.char = { }
-nodes.processors.char.proc = { }
+storage.shared.attributes_last_private = storage.shared.attributes_last_private or 127
-function nodes.report(t,done)
- 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)))
- else
- texio.write(string.format("<+ %s>",nodes.count(t)))
- end
- else
- if status.output_active then
- texio.write(string.format("<-- %s>",nodes.count(t)))
- else
- texio.write(string.format("<- %s>",nodes.count(t)))
- end
+function attributes.private(name) -- at the lua end (hidden from user)
+ local number = numbers[name]
+ if not number then
+ local last = storage.shared.attributes_last_private or 127
+ if last < 255 then
+ last = last + 1
+ storage.shared.attributes_last_private = last
end
+ number = last
+ numbers[name], names[number], list[number] = number, name, { }
end
+ return number
end
-do
-
- local hlist, vlist = node.id('hlist'), node.id('vlist')
-
- local function count(stack,flat)
- local n = 0
- while stack do
- local id = stack.id
- if not flat and id == hlist or id == vlist then
- local list = stack.list
- if list then
- n = n + 1 + count(list) -- self counts too
- else
- n = n + 1
- end
- else
- n = n + 1
- end
- stack = stack.next
- end
- return n
- end
-
- nodes.count = count
-
-end
+--[[ldx--
+<p>Access to nodes is what gives <l n='luatex'/> its power. Here we
+implement a few helper functions. These functions are rather optimized.</p>
+--ldx]]--
--[[ldx--
<p>When manipulating node lists in <l n='context'/>, we will remove
@@ -264,779 +98,135 @@ into the <l n='tex'/> engine, but this is a not so natural extension.</p>
also ignore the empty nodes. [This is obsolete!]</p>
--ldx]]--
-
---[[ldx--
-<p>Serializing nodes can be handy for tracing. Also, saving and
-loading node lists can come in handy as soon we are going to
-use external applications to process node lists.</p>
---ldx]]--
-
-function nodes.show(stack)
---~ texio.write_nl(table.serialize(stack))
-end
-
-function nodes.save(stack,name) -- *.ltn : luatex node file
---~ if name then
---~ file.savedata(name,table.serialize(stack))
---~ else
---~ texio.write_nl('log',table.serialize(stack))
---~ end
-end
-
-function nodes.load(name)
---~ return file.loaddata(name)
-end
-
--- node-cap.lua
-
---~ nodes.capture = { } -- somehow fails
-
---~ function nodes.capture.start(cbk)
---~ local head, tail = nil, nil
---~ callbacks.push(cbk, function(t)
---~ if tail then
---~ tail.next = t
---~ else
---~ head, tail = t, t
---~ end
---~ while tail.next do
---~ tail = tail.next
---~ end
---~ return false
---~ end)
---~ function nodes.capture.stop()
---~ function nodes.capture.stop() end
---~ function nodes.capture.get()
---~ function nodes.capture.get() end
---~ return head
---~ end
---~ callbacks.pop(cbk)
---~ end
---~ function nodes.capture.get() end -- error
---~ end
-
---~ nodes.capture.stop = function() end
---~ nodes.capture.get = function() end
-
--- node-gly.lua
-
-if not fonts then fonts = { } end
-if not fonts.otf then fonts.otf = { } end
-if not fonts.tfm then fonts.tfm = { } end
-if not fonts.tfm.id then fonts.tfm.id = { } end
-
-do
-
- local glyph = node.id('glyph')
- local has_attribute = node.has_attribute
- local traverse_id = node.traverse_id
-
- local pairs = pairs
-
- local starttiming, stoptiming = input.starttiming, input.stoptiming
-
- function nodes.process_characters(head)
- -- not ok yet; we need a generic blocker
- -- if status.output_active then
- if false then -- status.output_active then
- return head, false -- true
+nodes = nodes or { }
+
+local hlist = node.id('hlist')
+local vlist = node.id('vlist')
+local glyph = node.id('glyph')
+local glue = node.id('glue')
+local penalty = node.id('penalty')
+local kern = node.id('kern')
+local whatsit = node.id('whatsit')
+
+local traverse_id = node.traverse_id
+local traverse = node.traverse
+local free_node = node.free
+local remove_node = node.remove
+
+function nodes.remove(head, current, free_too)
+ local t = current
+ head, current = remove_node(head,current)
+ if t then
+ if free_too then
+ free_node(t)
+ t = nil
else
- -- either next or not, but definitely no already processed list
- starttiming(nodes)
- local usedfonts, attrfonts, done = { }, { }, false
- -- todo: should be independent of otf
- local set_dynamics, font_ids = fonts.otf.set_dynamics, fonts.tfm.id -- todo: font-var.lua so that we can global this one
- local a, u, prevfont, prevattr = 0, 0, nil, 0
- for n in traverse_id(glyph,head) do
- local font, attr = n.font, has_attribute(n,0) -- zero attribute is reserved for fonts, preset to 0 is faster (first match)
- if attr and attr > 0 then
- if font ~= prevfont or attr ~= prevattr then
- local used = attrfonts[font]
- if not used then
- used = { }
- attrfonts[font] = used
- end
- if not used[attr] then
- local d = set_dynamics(font_ids[font],attr) -- todo, script, language -> n.language also axis
- if d then
- used[attr] = d
- a = a + 1
- end
- end
- prevfont, prevattr = font, attr
- end
- elseif font ~= prevfont then
- prevfont, prevattr = font, 0
- local used = usedfonts[font]
- if not used then
- local data = font_ids[font]
- if data then
- local shared = data.shared -- we need to check shared, only when same features
- if shared then
- local processors = shared.processors
- if processors and #processors > 0 then
- usedfonts[font] = processors
- u = u + 1
- end
- end
- else
- -- probably nullfont
- end
- end
- else
- prevattr = attr
- end
- end
- -- we could combine these and just make the attribute nil
- if u > 0 then
- for font, processors in pairs(usedfonts) do
- local n = #processors
- if n == 1 then
- local h, d = processors[1](head,font,false)
- head, done = h or head, done or d
- else
- for i=1,#processors do
- local h, d = processors[i](head,font,false)
- head, done = h or head, done or d
- end
- end
- end
- end
- if a > 0 then -- we need to get rid of a loop here
- for font, dynamics in pairs(attrfonts) do
- for attribute, processors in pairs(dynamics) do -- attr can switch in between
- local n = #processors
- if n == 1 then
- local h, d = processors[1](head,font,attribute)
- head, done = h or head, done or d
- else
- for i=1,n do
- local h, d = processors[i](head,font,attribute)
- head, done = h or head, done or d
- end
- end
- end
- end
- end
- stoptiming(nodes)
- if nodes.trace then
- nodes.report(head,done)
- end
- return head, true
+ t.next, t.prev = nil, nil
end
- end
-
+ end
+ return head, current, t
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
+function nodes.delete(head,current)
+ return nodes.remove(head,current,true)
+end
-do
+nodes.before = node.insert_before
+nodes.after = node.insert_after
- local has_attribute, set, attribute = node.has_attribute, node.set_attribute, tex.attribute
+-- we need to test this, as it might be fixed now
- function nodes.inherit_attributes(n) -- still ok ?
- if n then
- local i = 1
- while true do
- local a = attribute[i]
- if a < 0 then
- break
- else
- local ai = has_attribute(n,i)
- if not ai then
- set(n,i,a)
- end
- i = i + 1
- end
+function nodes.before(h,c,n)
+ if c then
+ if c == h then
+ n.next = h
+ n.prev = nil
+ h.prev = n
+ else
+ local cp = c.prev
+ n.next = c
+ n.prev = cp
+ if cp then
+ cp.next = n
end
+ c.prev = n
+ return h, n
end
end
-
-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
-
---~ nodes.processors.actions = nodes.processors.actions or { }
-
---~ function nodes.processors.action(head)
---~ if head then
---~ node.slide(head)
---~ local done = false
---~ local actions = nodes.processors.actions
---~ for i=1,#actions do
---~ local h, ok = actions[i](head)
---~ if ok then
---~ head, done = h, true
---~ end
---~ end
---~ if done then
---~ return head
---~ else
---~ return true
---~ end
---~ else
---~ return head
---~ end
---~ end
-
-lists = lists or { }
-lists.plugins = lists.plugins or { }
-
-chars = chars or { }
-chars.plugins = chars.plugins or { }
-
---~ words = words or { }
---~ words.plugins = words.plugins or { }
-
-callbacks.trace = false
-
-do
-
- kernel = kernel or { }
-
- local starttiming, stoptiming = input.starttiming, input.stoptiming
- local hyphenate, ligaturing, kerning = lang.hyphenate, node.ligaturing, node.kerning
-
- function kernel.hyphenation(head,tail) -- lang.hyphenate returns done
- starttiming(kernel)
- local done = hyphenate(head,tail)
- stoptiming(kernel)
- return head, tail, done
- end
- function kernel.ligaturing(head,tail) -- node.ligaturing returns head,tail,done
- starttiming(kernel)
- local head, tail, done = ligaturing(head,tail)
- stoptiming(kernel)
- return head, tail, done
- end
- function kernel.kerning(head,tail) -- node.kerning returns head,tail,done
- starttiming(kernel)
- local head, tail, done = kerning(head,tail)
- stoptiming(kernel)
- return head, tail, done
- end
-
-end
-
-callback.register('hyphenate' , function(head,tail) return tail end)
-callback.register('ligaturing', function(head,tail) return tail end)
-callback.register('kerning' , function(head,tail) return tail end)
-
--- used to be loop, this is faster, called often; todo: shift up tail or even better,
--- handle tail everywhere; for the moment we're safe
-
-do
-
- local charplugins, listplugins = chars.plugins, lists.plugins
-
- nodes.processors.actions = function(head,tail) -- removed: if head ... end
- local ok, done = false, false
- head, ok = nodes.process_attributes(head,charplugins) ; done = done or ok -- attribute driven
- head, tail, ok = kernel.hyphenation (head,tail) ; done = done or ok -- language driven
- head, ok = languages.words.check (head,tail) ; done = done or ok -- language driven
- head, ok = nodes.process_characters(head) ; done = done or ok -- font driven
- ok = nodes.protect_glyphs (head) ; done = done or ok -- turn chars into glyphs
- head, tail, ok = kernel.ligaturing (head,tail) ; done = done or ok -- normal ligaturing routine / needed for base mode
- head, tail, ok = kernel.kerning (head,tail) ; done = done or ok -- normal kerning routine / needed for base mode
- head, ok = nodes.process_attributes(head,listplugins) ; done = done or ok -- attribute driven
- return head, done
- end
-
+ return n, n
end
-do
-
- local actions = nodes.processors.actions
- local first_character = node.first_character
- local slide = node.slide
-
- local function tracer(what,state,head,groupcode,glyphcount)
- texio.write_nl(string.format("%s %s: group: %s, nodes: %s",
- (state and "Y") or "N", what, groupcode or "?", nodes.count(head,true)))
- end
-
- function nodes.processors.pre_linebreak_filter(head,groupcode) -- todo: tail
- local first, found = first_character(head)
- if found then
- if callbacks.trace then tracer("pre_linebreak",true,head,groupcode) end
- local head, done = actions(head,slide(head))
- return (done and head) or true
+function nodes.after(h,c,n)
+ if c then
+ local cn = c.next
+ if cn then
+ n.next = cn
+ cn.prev = n
else
- if callbacks.trace then tracer("pre_linebreak",false,head,groupcode) end
- return true
+ n.next = nil
end
+ c.next = n
+ n.prev = c
+ return h, n
end
-
- function nodes.processors.hpack_filter(head,groupcode) -- todo: tail
- local first, found = first_character(head)
- if found then
- if callbacks.trace then tracer("hpack",true,head,groupcode) end
- local head, done = actions(head,slide(head))
- return (done and head) or true
- end
- if callbacks.trace then tracer("hpack",false,head,groupcode) end
- return true
- end
-
+ return n, n
end
-callback.register('pre_linebreak_filter', nodes.processors.pre_linebreak_filter)
-callback.register('hpack_filter' , nodes.processors.hpack_filter)
-
-do
-
- -- beware, some field names will change in a next release of luatex
-
- local expand = table.tohash {
- "list", -- list_ptr & ins_ptr & adjust_ptr
- "pre", --
- "post", --
- "spec", -- glue_ptr
- "top_skip", --
- "attr", --
- "replace", -- nobreak
- "components", -- lig_ptr
- "box_left", --
- "box_right", --
- "glyph", -- margin_char
- "leader", -- leader_ptr
- "action", -- action_ptr
- "value", -- user_defined nodes with subtype 'a' en 'n'
- }
-
- -- page_insert: "height", "last_ins_ptr", "best_ins_ptr"
- -- split_insert: "height", "last_ins_ptr", "best_ins_ptr", "broken_ptr", "broken_ins"
-
- local ignore = table.tohash {
- "page_insert",
- "split_insert",
- "ref_count",
- }
-
- local dimension = table.tohash {
- "width", "height", "depth", "shift",
- "stretch", "shrink",
- "xoffset", "yoffset",
- "surround",
- "kern",
- "box_left_width", "box_right_width"
- }
-
- -- flat: don't use next, but indexes
- -- verbose: also add type
- -- can be sped up
-
- nodes.dimensionfields = dimension
- nodes.listablefields = expand
- nodes.ignorablefields = ignore
-
- -- not ok yet:
-
- function nodes.astable(n,sparse) -- not yet ok
- local f, t = node.fields(n.id,n.subtype), { }
- for i=1,#f do
- local v = f[i]
- local d = n[v]
- if d then
- if ignore[v] or v == "id" then
- -- skip
- elseif expand[v] then -- or: type(n[v]) ~= "string" or type(n[v]) ~= "number" or type(n[v]) ~= "table"
- t[v] = "pointer to list"
- elseif sparse then
- if (type(d) == "number" and d ~= 0) or (type(d) == "string" and d ~= "") then
- t[v] = d
- end
- else
- t[v] = d
- end
- end
- end
- t.type = node.type(n.id)
- return t
- end
-
- local nodefields = node.fields
- local nodetype = node.type
-
- -- under construction:
-
- local function totable(n,flat,verbose)
- local function to_table(n)
- local f = nodefields(n.id,n.subtype)
- local tt = { }
- for k=1,#f do
- local v = f[k]
- local nv = n[v]
- if nv then
- if ignore[v] then
- -- skip
- elseif expand[v] then
- if type(nv) == "number" or type(nv) == "string" then
- tt[v] = nv
- else
- tt[v] = totable(nv,flat,verbose)
- end
- elseif type(nv) == "table" then
- tt[v] = nv -- totable(nv,flat,verbose) -- data
- else
- tt[v] = nv
- end
- end
- end
- if verbose then
- tt.type = nodetype(tt.id)
- end
- return tt
+function nodes.replace(head,current,new)
+ if current and next then
+ local p, n = current.prev, current.next
+ new.prev, new.next = p, n
+ if p then
+ p.next = new
+ else
+ head = new
end
if n then
- if flat then
- local t = { }
- while n do
- t[#t+1] = to_table(n)
- n = n.next
- end
- return t
- else
- local t = to_table(n)
- if n.next then
- t.next = totable(n.next,flat,verbose)
- end
- return t
- end
- else
- return { }
+ n.prev = new
end
+ free_node(current)
end
+ return head, current
+end
- nodes.totable = totable
-
- local function key(k)
- return ((type(k) == "number") and "["..k.."]") or k
- end
-
- -- not ok yet:
+-- will move
- 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 = ""
- local tname = type(name)
- if tname == "string" then
- if name == "return" then
- handle("return {")
- else
- handle(name .. "={")
- end
- elseif tname == "number"then
- handle("[" .. name .. "]={")
- else
- handle("t={")
- end
- end
- if root then
- local fld
- if root.id then
- fld = nodefields(root.id,root.subtype) -- we can cache these (todo)
+local function count(stack,flat)
+ local n = 0
+ while stack do
+ local id = stack.id
+ if not flat and id == hlist or id == vlist then
+ local list = stack.list
+ if list then
+ n = n + 1 + count(list) -- self counts too
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 == "ref_count" then
- -- skip
- elseif k then
- local v = root[k]
- local t = type(v)
- if t == "number" then
- if v == 0 then
- -- skip
- else
- handle(("%s %s=%s,"):format(depth,key(k),v))
- end
- elseif t == "string" then
- if v == "" then
- -- skip
- else
- handle(("%s %s=%q,"):format(depth,key(k),v))
- end
- 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)
+ n = 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, 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
-
- function nodes.check_for_leaks(sparse)
- local l = { }
- local q = node.usedlist()
- for p in node.traverse(q) do
- local s = table.serialize(nodes.astable(p,sparse),node.type(p.id))
- l[s] = (l[s] or 0) + 1
- end
- node.flush_list(q)
- for k, v in pairs(l) do
- texio.write_nl(string.format("%s * %s", v, k))
- end
- end
-
-end
-
-if not node.list_has_attribute then -- no longer needed
-
- 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
+ n = n + 1
end
- return false
+ stack = stack.next
end
-
+ return n
end
-function nodes.pack_list(head)
- local t = { }
- for n in node.traverse(head) do
- t[#t+1] = tostring(n)
- end
- return t
-end
-
-do
+nodes.count = count
- local glue, whatsit, hlist = node.id("glue"), node.id("whatsit"), node.id("hlist")
+-- new
- function nodes.leftskip(n)
- while n do
- local id = n.id
- if id == glue then
- if n.subtype == 8 then -- 7 in c/web source
- return (n.spec and n.spec.width) or 0
- else
- return 0
- end
- elseif id == whatsit then
- n = n.next
- elseif id == hlist then
- return n.width
- else
- break
- end
+function attributes.ofnode(n)
+ local a = n.attr
+ if a then
+ local names = attributes.names
+ a = a.next
+ while a do
+ local number, value = a.number, a.value
+ texio.write_nl(format("%s : attribute %3i, value %4i, name %s",tostring(n),number,value,names[number] or '?'))
+ a = a.next
end
- return 0
- end
- function nodes.rightskip(n)
- if n then
- n = node.slide(n)
- while n do
- local id = n.id
- if id == glue then
- if n.subtype == 9 then -- 8 in the c/web source
- return (n.spec and n.spec.width) or 0
- else
- return 0
- end
- elseif id == whatsit then
- n = n.prev
- else
- break
- end
- end
- end
- return false
- end
-
+ end
end
--- goodie
---
--- if node.valid(tex.box[0]) then print("valid node") end
-
---~ do
---~ local n = node.new(0,0)
---~ local m = getmetatable(n)
---~ m.__metatable = 'node'
---~ node.free(n)
-
---~ function node.valid(n)
---~ return n and getmetatable(n) == 'node'
---~ end
---~ end
-
--- for the moment we put this here:
-
-do
-
- nodes.tracers = { }
- nodes.tracers.characters = { }
-
- local glyph, disc = node.id('glyph'), node.id('disc')
-
- local fontdata = fonts.tfm.id
-
- local function collect(head,list,tag,n)
- n = n or 0
- local ok, fn = false, nil
- while head do
- local id = head.id
- if id == glyph then
- local f = head.font
- if f ~= fn then
- ok, fn = false, f
- end
- local c = head.char
- local d = fontdata[f].characters[c]
- local i = (d and d.description.index) or -1
- if not ok then
- ok = true
- n = n + 1
- list[n] = list[n] or { }
- list[n][tag] = { }
- end
- local l = list[n][tag]
- l[#l+1] = { c, f, i }
- elseif id == disc then
- -- skip
- else
- ok = false
- end
- head = head.next
- end
- end
-
- function nodes.tracers.characters.equal(ta, tb)
- if #ta ~= #tb then
- return false
- else
- for i=1,#ta do
- local a, b = ta[i], tb[i]
- if a[1] ~= b[1] or a[2] ~= b[2] or a[3] ~= b[3] then
- return false
- end
- end
- end
- return true
- end
- function nodes.tracers.characters.string(t)
- local tt = { }
- for i=1,#t do
- tt[i] = utf.char(t[i][1])
- end
- return table.concat(tt,"")
- end
- function nodes.tracers.characters.unicodes(t,decimal)
- local tt = { }
- for i=1,#t do
- if decimal then
- tt[i] = t[i][1]
- else
- tt[i] = string.format("%04X",t[i][1])
- end
- end
- return table.concat(tt," ")
- end
- function nodes.tracers.characters.indices(t,decimal)
- local tt = { }
- for i=1,#t do
- if decimal then
- tt[i] = t[i][3]
- else
- tt[i] = string.format("%04X",t[i][3])
- end
- end
- return table.concat(tt," ")
- end
- function nodes.tracers.characters.fonts(t)
- local f = t[1] and t[1][2]
- return (f and file.basename(fontdata[f].filename or "unknown")) or "unknown"
- end
-
- function nodes.tracers.characters.start()
- local npc = nodes.process_characters
- local list = { }
- function nodes.process_characters(head)
- local n = #list
- collect(head,list,'before',n)
- local h, d = npc(head)
- collect(head,list,'after',n)
- if #list > n then
- list[#list+1] = { }
- end
- return h, d
- end
- function nodes.tracers.characters.stop()
- tracers.list['characters'] = list
- lmx.set('title', 'ConTeXt Character Processing Information')
- lmx.set('color-background-one', lmx.get('color-background-yellow'))
- lmx.set('color-background-two', lmx.get('color-background-purple'))
- lmx.show('context-characters.lmx')
- lmx.restore()
- nodes.process_characters = npc
- end
- end
+local left, space = lpeg.P("<"), lpeg.P(" ")
- local stack = { }
-
- function nodes.tracers.start(tag)
- stack[#stack+1] = tag
- local tracer = nodes.tracers[tag]
- if tracer and tracer.start then
- tracer.start()
- end
- end
- function nodes.tracers.stop()
- local tracer = stack[#stack]
- if tracer and tracer.stop then
- tracer.stop()
- end
- stack[#stack] = nil
- end
-
-end
+nodes.filterkey = left * (1-left)^0 * left * space^0 * lpeg.C((1-space)^0)