diff options
Diffstat (limited to 'tex/context/base/mkxl/attr-ini.lmt')
-rw-r--r-- | tex/context/base/mkxl/attr-ini.lmt | 352 |
1 files changed, 352 insertions, 0 deletions
diff --git a/tex/context/base/mkxl/attr-ini.lmt b/tex/context/base/mkxl/attr-ini.lmt new file mode 100644 index 000000000..ca21365cb --- /dev/null +++ b/tex/context/base/mkxl/attr-ini.lmt @@ -0,0 +1,352 @@ +if not modules then modules = { } end modules ['attr-ini'] = { + version = 1.001, + comment = "companion to attr-ini.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local next, type = next, type +local osexit = os.exit +local sortedhash = table.sortedhash + +--[[ldx-- +<p>We start with a registration system for atributes so that we can use the +symbolic names later on.</p> +--ldx]]-- + +local nodes = nodes +local context = context +local storage = storage +local commands = commands + +local implement = interfaces.implement + +attributes = attributes or { } +local attributes = attributes + +local sharedstorage = storage.shared + +local texsetattribute = tex.setattribute + +attributes.names = attributes.names or { } +attributes.numbers = attributes.numbers or { } +attributes.list = attributes.list or { } +attributes.values = attributes.values or { } +attributes.counts = attributes.counts or { } +attributes.handlers = attributes.handlers or { } +attributes.states = attributes.states or { } +attributes.unsetvalue = -0x7FFFFFFF + +local currentfont = font.current +local currentattributes = nodes and nodes. currentattributes or node.currentattributes +local getusedattributes = nodes and nodes.nuts and nodes.nuts.getusedattributes or node.direct.getusedattributes + +local names = attributes.names +local numbers = attributes.numbers +local list = attributes.list +local values = attributes.values +local counts = attributes.counts + +storage.register("attributes/names", names, "attributes.names") +storage.register("attributes/numbers", numbers, "attributes.numbers") +storage.register("attributes/list", list, "attributes.list") +storage.register("attributes/values", values, "attributes.values") +storage.register("attributes/counts", counts, "attributes.counts") + +local report_attribute = logs.reporter("attributes") +local report_value = logs.reporter("attributes","values") + +local trace_values = false + +trackers.register("attributes.values", function(v) trace_values = v end) + +-- function attributes.define(name,number) -- at the tex end +-- if not numbers[name] then +-- numbers[name] = number +-- names[number] = name +-- list[number] = { } +-- end +-- end + +--[[ldx-- +<p>We reserve this one as we really want it to be always set (faster).</p> +--ldx]]-- + +names[0], numbers["fontdynamic"] = "fontdynamic", 0 + +--[[ldx-- +<p>private attributes are used by the system and public ones are for users. We use dedicated +ranges of numbers for them. Of course a the <l n='context'/> end a private attribute can be +accessible too, so a private attribute can have a public appearance.</p> +--ldx]]-- + +sharedstorage.attributes_last_private = sharedstorage.attributes_last_private or 15 -- very private +sharedstorage.attributes_last_public = sharedstorage.attributes_last_public or 1024 -- less private + +function attributes.private(name) -- at the lua end (hidden from user) + local number = numbers[name] + if not number then + local last = sharedstorage.attributes_last_private + if last < 1023 then + last = last + 1 + sharedstorage.attributes_last_private = last + else + report_attribute("no more room for private attributes") + osexit() + end + number = last + numbers[name], names[number], list[number] = number, name, { } + end + return number +end + +function attributes.public(name) -- at the lua end (hidden from user) + local number = numbers[name] + if not number then + local last = sharedstorage.attributes_last_public + if last < 65535 then + last = last + 1 + sharedstorage.attributes_last_public = last + else + report_attribute("no more room for public attributes") + osexit() + end + number = last + numbers[name], names[number], list[number] = number, name, { } + end + return number +end + +attributes.system = attributes.private + +function attributes.define(name,category) + return (attributes[category or "public"] or attributes["public"])(name) +end + +-- tracers + +local function showlist(what,list) + if list then + local a = list.next + local i = 0 + while a do + local number = a.index + local value = a.value + i = i + 1 + report_attribute("%S %2i: attribute %3i, value %4i, name %a",what,i,number,value,names[number]) + a = a.next + end + end +end + +function attributes.showcurrent() + showlist("current",currentattributes()) +end + +function attributes.ofnode(n) + showlist(n,n.attr) +end + +-- rather special (can be optimized) + +local store = { } + +function attributes.save(name) + name = name or "" + local n = currentattributes() + n = n and n.next + local t = { } + while n do + t[n.index] = n.value + n = n.next + end + store[name] = { + attr = t, + font = currentfont(), + } +end + +function attributes.restore(name) + name = name or "" + local t = store[name] + if t then + local attr = t.attr + local font = t.font + if attr then + for k, v in next, attr do + texsetattribute(k,v) + end + end + if font then + -- tex.font = font + -- context.getvalue(fonts.hashes.csnames[font]) + currentfont(font) + end + end + -- store[name] = nil +end + +-- value manager + +local cleaners = { } + +-- function attributes.registervalue(index,value) +-- local list = values[index] +-- local last +-- if list then +-- last = counts[index] + 1 +-- list[last] = value +-- else +-- last = 1 +-- values[index] = { value } +-- end +-- counts[index] = last +-- return last +-- end + +function attributes.registervalue(index,value) + local list = values[index] + local last + if list then + local c = counts[index] + if c and c[2] > 0 then + -- this can be an option + for i=c[1],c[2] do + if list[i] == nil then + if trace_values then + report_value("reusing slot %i for attribute %i in range (%i,%i)",i,index,c[1],c[2]) + end + c[1] = i + list[i] = value + return i + end + end + else + c = { 0, 0 } + end + last = c[2] + 1 + list[last] = value + c[1] = last + c[2] = last + if trace_values then + report_value("expanding to slot %i for attribute %i",last,index) + end + else + last = 1 + values[index] = { value } + counts[index] = { last, last } + if trace_values then + report_value("starting at slot %i for attribute %i",last,index) + end + end + return last +end + +function attributes.getvalue(index,value) + local list = values[index] + return list and list[value] or nil +end + +function attributes.hasvalues(index) + local list = values[index] + return list and next(list) and true or false +end + +function attributes.setcleaner(index,cleaner) + cleaners[index] = cleaner +end + +function attributes.checkvalues() +-- if true then +-- report_value("no checking done") +-- return +-- end + if next(values) then + local active = getusedattributes() + if trace_values then + -- sorted + for index, list in sortedhash(values) do + local b = active[index] + if b then + local cleaner = cleaners[index] + for k in sortedhash(list) do + if b[k] then + report_value("keeping value %i for attribute %i",k,index) + else + report_value("wiping value %i for attribute %i",k,index) + if cleaner then + cleaner(list[k]) + end + list[k] = nil + end + end + if next(list) then + counts[index][1] = 0 + goto continue + end + end + report_value("no more values for attribute %i",index) + values[index] = nil + counts[index] = nil + ::continue:: + end + else + for index, list in next, values do + local b = active[index] + if b then + local cleaner = cleaners[index] + for k in next, list do + if not b[k] then + if cleaner then + cleaner(list[k]) + end + list[k] = nil + end + end + if next(list) then + counts[index][1] = 0 + goto continue + end + end + values[index] = nil + counts[index] = { 0, 0 } + ::continue:: + end + end + elseif trace_values then + report_value("no check needed") + end +end + +implement { + name = "cleanupattributes", + -- public = true, -- some day ... but then also \shipoutpage + protected = true, + actions = attributes.checkvalues, +} + +-- interface + +implement { + name = "defineattribute", + arguments = "2 strings", + actions = { attributes.define, context } +} + +implement { + name = "showattributes", + actions = attributes.showcurrent +} + +implement { + name = "savecurrentattributes", + arguments = "string", + actions = attributes.save +} + +implement { + name = "restorecurrentattributes", + arguments = "string", + actions = attributes.restore +} |