summaryrefslogtreecommitdiff
path: root/tex/context/base/mkiv/strc-ini.lua
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/mkiv/strc-ini.lua')
-rw-r--r--tex/context/base/mkiv/strc-ini.lua383
1 files changed, 383 insertions, 0 deletions
diff --git a/tex/context/base/mkiv/strc-ini.lua b/tex/context/base/mkiv/strc-ini.lua
new file mode 100644
index 000000000..7a6153096
--- /dev/null
+++ b/tex/context/base/mkiv/strc-ini.lua
@@ -0,0 +1,383 @@
+if not modules then modules = { } end modules ['strc-ini'] = {
+ version = 1.001,
+ comment = "companion to strc-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+--[[
+The restructuring is the (intermediate) result of quite some experiments. I started
+with the basic structure, followed by lists, numbers, enumerations, itemgroups
+and floats. All these have something in common, like pagenumbers and section
+prefixes. I played with some generic datastructure (in order to save space) but
+the code at both the lua and tex end then quickly becomes messy due to the fact
+that access to variables is too different. So, eventually I ended up with
+dedicated structures combined with sharing data. In lua this is quite efficient
+because tables are referenced. However, some precautions are to be taken in
+order to keep the utility file small. Utility data and process data share much
+but it does not make sense to store all processdata.
+
+]]--
+
+local lpegmatch = lpeg.match
+local type, next, tonumber, select = type, next, tonumber, select
+
+local formatters = string.formatters
+local settings_to_array = utilities.parsers.settings_to_array
+local settings_to_hash = utilities.parsers.settings_to_hash
+local allocate = utilities.storage.allocate
+
+local catcodenumbers = catcodes.numbers -- better use the context(...) way to switch
+
+local ctxcatcodes = catcodenumbers.ctxcatcodes
+local xmlcatcodes = catcodenumbers.xmlcatcodes
+local notcatcodes = catcodenumbers.notcatcodes
+local txtcatcodes = catcodenumbers.txtcatcodes
+
+local context = context
+local commands = commands
+
+local trace_processors = false
+local report_processors = logs.reporter("processors","structure")
+
+trackers.register("typesetters.processors", function(v) trace_processors = v end)
+
+local xmlconvert = lxml.convert
+local xmlstore = lxml.store
+
+local ctx_pushcatcodes = context.pushcatcodes
+local ctx_popcatcodes = context.popcatcodes
+local ctx_xmlsetup = context.xmlsetup
+local ctx_xmlprocessbuffer = context.xmlprocessbuffer
+
+-- -- -- namespace -- -- --
+
+-- This is tricky: we have stored and initialized already some of
+-- the job.registered tables so we have a forward reference!
+
+structures = structures or { }
+local structures = structures
+
+structures.blocks = structures.blocks or { }
+structures.sections = structures.sections or { }
+structures.pages = structures.pages or { }
+structures.registers = structures.registers or { }
+structures.references = structures.references or { }
+structures.lists = structures.lists or { }
+structures.helpers = structures.helpers or { }
+structures.documents = structures.documents or { }
+structures.notes = structures.notes or { }
+structures.descriptions = structures.descriptions or { }
+structures.itemgroups = structures.itemgroups or { }
+structures.specials = structures.specials or { }
+structures.counters = structures.counters or { }
+structures.tags = structures.tags or { }
+structures.formulas = structures.formulas or { } -- not used but reserved
+structures.sets = structures.sets or { }
+structures.marks = structures.marks or { }
+structures.floats = structures.floats or { }
+structures.synonyms = structures.synonyms or { }
+
+--~ table.print(structures)
+
+local processors = typesetters.processors
+
+-- -- -- specials -- -- --
+
+-- we can store information and get back a reference; this permits
+-- us to store rather raw data in references
+
+local specials = structures.specials
+
+local collected = allocate()
+local tobesaved = allocate()
+
+specials.collected = collected
+specials.tobesaved = tobesaved
+
+local function initializer()
+ collected = specials.collected
+ tobesaved = specials.tobesaved
+end
+
+if job then
+ job.register('structures.specials.collected', tobesaved, initializer)
+end
+
+function specials.store(class,data)
+ if class and data then
+ local s = tobesaved[class]
+ if not s then
+ s = { }
+ tobesaved[class] = s
+ end
+ s[#s+1] = data
+ context(#s)
+ else
+ context(0)
+ end
+end
+
+function specials.retrieve(class,n)
+ if class and n then
+ local c = collected[class]
+ return c and c[n]
+ end
+end
+
+-- -- -- helpers -- -- --
+
+local helpers = structures.helpers
+
+-- function helpers.touserdata(str)
+-- local hash = str and str ~= "" and settings_to_hash(str)
+-- if hash and next(hash) then
+-- return hash
+-- end
+-- end
+
+function helpers.touserdata(data)
+ if type(data) == "string" then
+ if data == "" then
+ return nil
+ else
+ data = settings_to_hash(data)
+ end
+ end
+ if data and next(data) then
+ return data
+ end
+end
+
+local function simplify(d,nodefault)
+ if d then
+ local t = { }
+ for k, v in next, d do
+ local tv = type(v)
+ if tv == "table" then
+ if next(v) then
+ t[k] = simplify(v)
+ end
+ elseif tv == "string" then
+ if v ~= "" then
+ t[k] = v
+ end
+ elseif tv == "boolean" then
+ if v then
+ t[k] = v
+ end
+ else
+ t[k] = v
+ end
+ end
+ return next(t) and t
+ elseif nodefault then
+ return nil
+ else
+ return { }
+ end
+end
+
+-- we only care about the tuc file so this would do too:
+--
+-- local function simplify(d,nodefault)
+-- if d then
+-- for k, v in next, d do
+-- local tv = type(v)
+-- if tv == "string" then
+-- if v == "" or v == "default" then
+-- d[k] = nil
+-- end
+-- elseif tv == "table" then
+-- if next(v) then
+-- simplify(v)
+-- end
+-- elseif tv == "boolean" then
+-- if not v then
+-- d[k] = nil
+-- end
+-- end
+-- end
+-- return d
+-- elseif nodefault then
+-- return nil
+-- else
+-- return { }
+-- end
+-- end
+
+helpers.simplify = simplify
+
+function helpers.merged(...)
+ local t = { }
+ for k=1, select("#",...) do
+ local v = select(k,...)
+ if v and v ~= "" and not t[k] then
+ t[k] = v
+ end
+ end
+ return t
+end
+
+local tags = {
+ generic = "ctx:genericentry",
+ section = "ctx:sectionentry",
+ entry = "ctx:registerentry",
+}
+
+-- We had the following but it overloads the main document so it's a no-go as we
+-- no longer push and pop. So now we use the tag as buffername, namespace and also
+-- (optionally) as a setups to be applied but keep in mind that document setups
+-- also get applied (when they use #1's).
+--
+-- local command = formatters["\\xmlprocessbuffer{%s}{%s}{}"](metadata.xmlroot or "main",tag)
+
+local experiment = true
+
+function helpers.title(title,metadata) -- coding is xml is rather old and not that much needed now
+ if title and title ~= "" then -- so it might disappear
+ if metadata then
+ local xmlsetup = metadata.xmlsetup
+ if metadata.coding == "xml" then
+ -- title can contain raw xml
+ local tag = tags[metadata.kind] or tags.generic
+ local xmldata = formatters["<?xml version='1.0'?><%s>%s</%s>"](tag,title,tag)
+ if not experiment then
+ buffers.assign(tag,xmldata)
+ end
+ if trace_processors then
+ report_processors("putting xml data in buffer: %s",xmldata)
+ report_processors("processing buffer with setup %a and tag %a",xmlsetup,tag)
+ end
+ if experiment then
+ -- the question is: will this be forgotten ... better store in a via file
+ local xmltable = xmlconvert("temp",xmldata or "")
+ xmlstore("temp",xmltable)
+ ctx_xmlsetup("temp",xmlsetup or "")
+ else
+ ctx_xmlprocessbuffer("dummy",tag,xmlsetup or "")
+ end
+ elseif xmlsetup then -- title is reference to node (so \xmlraw should have been used)
+ if trace_processors then
+ report_processors("feeding xmlsetup %a using node %a",xmlsetup,title)
+ end
+ ctx_xmlsetup(title,metadata.xmlsetup)
+ else
+ local catcodes = metadata.catcodes
+ if catcodes == notcatcodes or catcodes == xmlcatcodes then
+ if trace_processors then
+ report_processors("catcodetable %a, overloads %a, text %a",ctxcatcodes,catcodes,title)
+ end
+ context(title) -- nasty
+ else
+ if trace_processors then
+ report_processors("catcodetable %a, text %a",catcodes,title)
+ end
+ --
+ -- context.sprint(catcodes,title)
+ --
+ -- doesn't work when a newline is in there \section{Test\ A} so we do
+ -- it this way:
+ --
+ ctx_pushcatcodes(catcodes)
+ context(title)
+ ctx_popcatcodes()
+ end
+ end
+ else
+ context(title) -- no catcode switch, was: texsprint(title)
+ end
+ end
+end
+
+-- -- -- sets -- -- --
+
+local sets = structures.sets
+
+sets.setlist = sets.setlist or { }
+
+storage.register("structures/sets/setlist", structures.sets.setlist, "structures.sets.setlist")
+
+local setlist = sets.setlist
+
+function sets.define(namespace,name,values,default,numbers)
+ local dn = setlist[namespace]
+ if not dn then
+ dn = { }
+ setlist[namespace] = dn
+ end
+ if values == "" then
+ dn[name] = { { }, default }
+ else
+ local split = settings_to_array(values)
+ if numbers then
+ -- convert to numbers (e.g. for reset)
+ for i=1,#split do
+ split[i] = tonumber(split[i]) or 0
+ end
+ end
+ dn[name] = { split, default }
+ end
+end
+
+function sets.getall(namespace,block,name)
+ local ds = setlist[namespace]
+ if not ds then
+ return { }
+ else
+ local dn
+ if block and block ~= "" then
+ dn = ds[block..":"..name] or ds[name] or ds[block] or ds.default
+ else
+ dn = ds[name] or ds.default
+ end
+ return (dn and dn[1]) or { }
+ end
+end
+
+-- messy (will be another keyword, fixedconversion) .. needs to be documented too
+-- maybe we should cache
+
+local splitter = lpeg.splitat("::")
+
+function sets.get(namespace,block,name,level,default) -- check if name is passed
+ --fixed::R:a: ...
+ local kind, rest = lpegmatch(splitter,name)
+ if rest and kind == "fixed" then -- fixed::n,a,i
+ local s = settings_to_array(rest)
+ return s[level] or s[#s] or default
+ end
+ --
+ local ds = setlist[namespace]
+ if not ds then
+ return default
+ end
+ local dn
+ if name and name ~= "" then
+ if block and block ~= "" then
+ dn = ds[block..":"..name] or ds[name] or ds[block] or ds.default
+ else
+ dn = ds[name] or ds.default
+ end
+ else
+ if block and block ~= "" then
+ dn = ds[block] or ds[block..":default"] or ds.default
+ else
+ dn = ds.default
+ end
+ end
+ if not dn then
+ return default
+ end
+ local dl = dn[1][level]
+ return dl or dn[2] or default
+end
+
+-- interface
+
+interfaces.implement {
+ name = "definestructureset",
+ actions = sets.define,
+ arguments = { "string", "string", "string", "string", "boolean" }
+}