diff options
Diffstat (limited to 'Master/texmf-dist/tex/context/base/strc-ref.lua')
-rw-r--r-- | Master/texmf-dist/tex/context/base/strc-ref.lua | 641 |
1 files changed, 505 insertions, 136 deletions
diff --git a/Master/texmf-dist/tex/context/base/strc-ref.lua b/Master/texmf-dist/tex/context/base/strc-ref.lua index eb4f74ce86f..475ab318a8a 100644 --- a/Master/texmf-dist/tex/context/base/strc-ref.lua +++ b/Master/texmf-dist/tex/context/base/strc-ref.lua @@ -1,13 +1,14 @@ if not modules then modules = { } end modules ['strc-ref'] = { version = 1.001, - comment = "companion to strc-ref.tex", + comment = "companion to strc-ref.mkiv", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", copyright = "PRAGMA ADE / ConTeXt Development Team", license = "see context related readme files" } -local format, find, gmatch, match = string.format, string.find, string.gmatch, string.match -local texsprint, texwrite, texcount = tex.sprint, tex.write, tex.count +local format, find, gmatch, match, concat = string.format, string.find, string.gmatch, string.match, table.concat +local lpegmatch = lpeg.match +local texsprint, texwrite, texcount, texsetcount = tex.sprint, tex.write, tex.count, tex.setcount local trace_referencing = false trackers.register("structure.referencing", function(v) trace_referencing = v end) @@ -18,42 +19,84 @@ local constants = interfaces.constants -- beware, this is a first step in the rewrite (just getting rid of -- the tuo file); later all access and parsing will also move to lua +-- the useddata and pagedata names might change +-- todo: pack exported data + jobreferences = jobreferences or { } jobreferences.tobesaved = jobreferences.tobesaved or { } jobreferences.collected = jobreferences.collected or { } -jobreferences.documents = jobreferences.documents or { } jobreferences.defined = jobreferences.defined or { } -- indirect ones jobreferences.derived = jobreferences.derived or { } -- taken from lists jobreferences.specials = jobreferences.specials or { } -- system references jobreferences.runners = jobreferences.runners or { } jobreferences.internals = jobreferences.internals or { } +jobreferences.exporters = jobreferences.exporters or { } +jobreferences.imported = jobreferences.imported or { } storage.register("jobreferences/defined", jobreferences.defined, "jobreferences.defined") local tobesaved, collected = jobreferences.tobesaved, jobreferences.collected -local defined, derived, specials, runners = jobreferences.defined, jobreferences.derived, jobreferences.specials, jobreferences.runners +local defined, derived, specials = jobreferences.defined, jobreferences.derived, jobreferences.specials +local exporters, runners = jobreferences.exporters, jobreferences.runners local currentreference = nil -jobreferences.initializers = jobreferences.initializers or { } +local initializers = { } +local finalizers = { } function jobreferences.registerinitializer(func) -- we could use a token register instead - jobreferences.initializers[#jobreferences.initializers+1] = func + initializers[#initializers+1] = func +end +function jobreferences.registerfinalizer(func) -- we could use a token register instead + finalizers[#finalizers+1] = func end local function initializer() tobesaved, collected = jobreferences.tobesaved, jobreferences.collected - for k,v in ipairs(jobreferences.initializers) do - v(tobesaved,collected) + for i=1,#initializers do + initializers[i](tobesaved,collected) + end +end +local function finalizer() + tobesaved = jobreferences.tobesaved + for i=1,#finalizers do + finalizers[i](tobesaved) end end if job then - job.register('jobreferences.collected', jobreferences.tobesaved, initializer) + job.register('jobreferences.collected', jobreferences.tobesaved, initializer, finalizer) end -- todo: delay split till later as in destinations we split anyway +local orders, lastorder = { }, 0 + +local function setnextorder(kind,name) + lastorder = 0 + if kind and name then + local ok = orders[kind] + if not ok then + ok = { } + orders[kind] = ok + end + lastorder = (ok[name] or 0) + 1 + ok[name] = lastorder + end + texsetcount("global","locationorder",lastorder) +end + +jobreferences.setnextorder = setnextorder + +function jobreferences.setnextinternal(kind,name) + setnextorder(kind,name) -- always incremented with internal + texsetcount("global","locationcount",texcount.locationcount + 1) +end + +function jobreferences.currentorder(kind,name) + texwrite((orders[kind] and orders[kind][name]) or lastorder) +end + function jobreferences.set(kind,prefix,tag,data) for ref in gmatch(tag,"[^,]+") do local p, r = match(ref,"^(%-):(.-)$") @@ -74,9 +117,9 @@ function jobreferences.set(kind,prefix,tag,data) end end -function jobreferences.setandgetattribute(kind,prefix,tag,data) -- maybe do internal automatically here +function jobreferences.setandgetattribute(kind,prefix,tag,data,view) -- maybe do internal automatically here jobreferences.set(kind,prefix,tag,data) - texcount.lastdestinationattribute = jobreferences.setinternalreference(prefix,tag) or -0x7FFFFFFF + texcount.lastdestinationattribute = jobreferences.setinternalreference(prefix,tag,nil,view) or -0x7FFFFFFF end function jobreferences.enhance(prefix,tag,spec) @@ -117,12 +160,12 @@ local special_reference = special * lparent * (operation * optional_arguments + local scanner = (reset * outer_reference * (special_reference + inner_reference)^-1 * -1) / function() return result end -function jobreferences.analyse(str) - return scanner:match(str) -end +--~ function jobreferences.analyse(str) -- overloaded +--~ return lpegmatch(scanner,str) +--~ end function jobreferences.split(str) - return scanner:match(str or "") + return lpegmatch(scanner,str or "") end --~ print(table.serialize(jobreferences.analyse(""))) @@ -147,7 +190,7 @@ function jobreferences.resolvers.section(var) local vi = structure.lists.collected[var.i[2]] if vi then var.i = vi - var.r = (vi.references and vi.references.realpage) or 1 + var.r = (vi.references and vi.references.realpage) or (vi.pagedata and vi.pagedata.realpage) or 1 else var.i = nil var.r = 1 @@ -163,7 +206,7 @@ function jobreferences.resolvers.reference(var) local vi = var.i[2] if vi then var.i = vi - var.r = (vi.references and vi.references.realpage) or 1 + var.r = (vi.references and vi.references.realpage) or (vi.pagedata and vi.pagedata.realpage) or 1 else var.i = nil var.r = 1 @@ -180,10 +223,13 @@ local function register_from_lists(collected,derived) local kind, realpage = m.kind, r.realpage if kind and realpage then local d = derived[prefix] if not d then d = { } derived[prefix] = d end ---~ d[reference] = { kind, i } -for s in gmatch(reference,"[^,]+") do - d[s] = { kind, i } -end + local t = { kind, i } + for s in gmatch(reference,"%s*([^,]+)") do + if trace_referencing then + logs.report("referencing","list entry %s provides %s reference '%s' on realpage %s",i,kind,s,realpage) + end + d[s] = t -- share them + end end end end @@ -217,6 +263,10 @@ function jobreferences.urls.get(name,method,space) -- method: none, before, afte end end +function commands.doifurldefinedelse(name) + commands.doifelse(urls[name]) +end + -- files jobreferences.files = jobreferences.files or { } @@ -237,6 +287,59 @@ function jobreferences.files.get(name,method,space) -- method: none, before, aft end end +function commands.doiffiledefinedelse(name) + commands.doifelse(files[name]) +end + +-- helpers + +function jobreferences.checkedfile(whatever) -- return whatever if not resolved + if whatever then + local w = files[whatever] + if w then + return w[1] + else + return whatever + end + end +end + +function jobreferences.checkedurl(whatever) -- return whatever if not resolved + if whatever then + local w = urls[whatever] + if w then + local u, f = w[1], w[2] + if f and f ~= "" then + return u .. "/" .. f + else + return u + end + else + return whatever + end + end +end + +function jobreferences.checkedfileorurl(whatever,default) -- return nil, nil if not resolved + if whatever then + local w = files[whatever] + if w then + return w[1], nil + else + local w = urls[whatever] + if w then + local u, f = w[1], w[2] + if f and f ~= "" then + return nil, u .. "/" .. f + else + return nil, u + end + end + end + end + return default +end + -- programs jobreferences.programs = jobreferences.programs or { } @@ -257,72 +360,213 @@ function jobreferences.programs.get(name) end end +function jobreferences.checkedprogram(whatever) -- return whatever if not resolved + if whatever then + local w = programs[whatever] + if w then + return w[1] + else + return whatever + end + end +end + -- shared by urls and files function jobreferences.whatfrom(name) texsprint(ctxcatcodes,(urls[name] and variables.url) or (files[name] and variables.file) or variables.unknown) end -function jobreferences.from(name,method,space) +--~ function jobreferences.from(name) +--~ local u = urls[name] +--~ if u then +--~ local url, file, description = u[1], u[2], u[3] +--~ if description ~= "" then +--~ texsprint(ctxcatcodes,format("\\dofromurldescription{%s}",description)) +--~ -- ok +--~ elseif file and file ~= "" then +--~ texsprint(ctxcatcodes,format("\\dofromurlliteral{%s}",url .. "/" .. file)) +--~ else +--~ texsprint(ctxcatcodes,format("\\dofromurlliteral{%s}",url)) +--~ end +--~ else +--~ local f = files[name] +--~ if f then +--~ local description, file = f[1], f[2] +--~ if description ~= "" then +--~ texsprint(ctxcatcodes,format("\\dofromfiledescription{%s}",description)) +--~ else +--~ texsprint(ctxcatcodes,format("\\dofromfileliteral{%s}",file)) +--~ end +--~ end +--~ end +--~ end + +function jobreferences.from(name) local u = urls[name] if u then local url, file, description = u[1], u[2], u[3] if description ~= "" then + context.dofromurldescription(description) -- ok elseif file and file ~= "" then - description = url .. "/" .. file + context.dofromurlliteral(url .. "/" .. file) else - description = url + context.dofromurlliteral(url) end - texsprint(ctxcatcodes,description) else local f = files[name] if f then local description, file = f[1], f[2] if description ~= "" then - -- + context.dofromfiledescription(description) else - description = file + context.dofromfileliteral(file) + end + end + end +end + +-- export + +exporters.references = exporters.references or { } +exporters.lists = exporters.lists or { } + +function exporters.references.generic(data) + local useddata = {} + local entries, userdata = data.entries, data.userdata + if entries then + for k, v in next, entries do + useddata[k] = v + end + end + if userdata then + for k, v in next, userdata do + useddata[k] = v + end + end + return useddata +end + +function exporters.lists.generic(data) + local useddata = { } + local titledata, numberdata = data.titledata, data.numberdata + if titledata then + useddata.title = titledata.title + end + if numberdata then + local numbers = numberdata.numbers + local t = { } + for i=1,#numbers do + local n = numbers[i] + if n ~= 0 then + t[#t+1] = n + end + end + useddata.number = concat(t,".") + end + return useddata +end + +local function referencer(data) + local references = data.references + local realpage = references.realpage + local numberdata = jobpages.tobesaved[realpage] + local specification = numberdata.specification + return { + realpage = references.realpage, + number = numberdata.number, + conversion = specification.conversion, + -- prefix = only makes sense when bywhatever + } +end + +function jobreferences.export(usedname) + local exported = { } + local e_references, e_lists = exporters.references, exporters.lists + local g_references, g_lists = e_references.generic, e_lists.generic + -- todo: pagenumbers + -- todo: some packing + for prefix, references in next, jobreferences.tobesaved do + local pe = exported[prefix] if not pe then pe = { } exported[prefix] = pe end + for key, data in next, references do + local metadata = data.metadata + local exporter = e_references[metadata.kind] or g_references + if exporter then + pe[key] = { + metadata = { + kind = metadata.kind, + catcodes = metadata.catcodes, + coding = metadata.coding, -- we can omit "tex" + }, + useddata = exporter(data), + pagedata = referencer(data), + } end - texsprint(ctxcatcodes,description) end end + local pe = exported[""] if not pe then pe = { } exported[""] = pe end + for n, data in next, structure.lists.tobesaved do + local metadata = data.metadata + local exporter = e_lists[metadata.kind] or g_lists + if exporter then + local result = { + metadata = { + kind = metadata.kind, + catcodes = metadata.catcodes, + coding = metadata.coding, -- we can omit "tex" + }, + useddata = exporter(data), + pagedata = referencer(data), + } + for key in gmatch(data.references.reference,"[^,]+") do + pe[key] = result + end + end + end + local e = { + references = exported, + version = 1.00, + } + io.savedata(file.replacesuffix(usedname or tex.jobname,"tue"),table.serialize(e,true)) end -function jobreferences.load(name) - if name then - local jdn = jobreferences.documents[name] +function jobreferences.import(usedname) + if usedname then + local imported = jobreferences.imported + local jdn = imported[usedname] if not jdn then - jdn = { } - local fn = files[name] - if fn then - jdn.filename = fn[1] - local data = io.loaddata(file.replacesuffix(fn[1],"tuc")) or "" - if data ~= "" then - -- quick and dirty, assume sane { } usage inside strings - local lists = data:match("structure%.lists%.collected=({.-[\n\r]+})[\n\r]") - if lists and lists ~= "" then - lists = loadstring("return" .. lists) - if lists then - jdn.lists = lists() - jdn.derived = { } - register_from_lists(jdn.lists,jdn.derived) - else - commands.writestatus("error","invalid structure data in %s",filename) - end - end - local references = data:match("jobreferences%.collected=({.-[\n\r]+})[\n\r]") - if references and references ~= "" then - references = loadstring("return" .. references) - if references then - jdn.references = references() - else - commands.writestatus("error","invalid reference data in %s",filename) - end - end + local filename = files[usedname] + if filename then -- only registered files + filename = filename[1] + else + filename = usedname + end + local data = io.loaddata(file.replacesuffix(filename,"tue")) or "" + if data == "" then + interfaces.showmessage("references",24,filename) + data = nil + else + data = loadstring(data) + if data then + data = data() + end + if data then + -- version check + end + if not data then + interfaces.showmessage("references",25,filename) end end - jobreferences.documents[name] = jdn + if data then + interfaces.showmessage("references",26,filename) + jdn = data + jdn.filename = filename + else + jdn = { filename = filename, references = { }, version = 1.00 } + end + imported[usedname] = jdn + imported[filename] = jdn end return jdn else @@ -330,6 +574,10 @@ function jobreferences.load(name) end end +function jobreferences.load(usedname) + -- gone +end + function jobreferences.define(prefix,reference,list) local d = defined[prefix] if not d then d = { } defined[prefix] = d end d[reference] = { "defined", list } @@ -366,7 +614,7 @@ local function resolve(prefix,reference,args,set) -- we start with prefix,refere if d then resolve(prefix,d[2],nil,set) else - local var = scanner:match(ri) + local var = lpegmatch(scanner,ri) if var then var.reference = ri if not var.outer and var.inner then @@ -438,6 +686,16 @@ function jobreferences.expandcurrent() -- todo: two booleans: o_has_tex& a_has_t end end +--~ local uo = urls[outer] +--~ if uo then +--~ special, operation, argument = "url", uo[1], inner or uo[2] -- maybe more is needed +--~ else +--~ local fo = files[outer] +--~ if fo then +--~ special, operation, argument = "file", fo[1], inner -- maybe more is needed +--~ end +--~ end + local function identify(prefix,reference) local set = resolve(prefix,reference) local bug = false @@ -455,6 +713,7 @@ local function identify(prefix,reference) -- special() var.kind = "special outer" end + var.f = outer elseif operation then if arguments then -- special(operation{argument,argument}) @@ -471,17 +730,37 @@ local function identify(prefix,reference) var.error = "unknown special" end elseif outer then - local e = jobreferences.load(outer) + local e = jobreferences.import(outer) if e then - local f = e.filename - if f then - if inner then - local r = e.references + if inner then + local r = e.references + if r then + r = r[prefix] + if r then + r = r[inner] + if r then + if arguments then + -- outer::inner{argument} + var.kind = "outer with inner with arguments" + else + -- outer::inner + var.kind = "outer with inner" + end + var.i = { "reference", r } + jobreferences.resolvers.reference(var) + var.f = outer + var.e = true -- external + end + end + end + if not r then + r = e.derived if r then r = r[prefix] if r then r = r[inner] if r then + -- outer::inner if arguments then -- outer::inner{argument} var.kind = "outer with inner with arguments" @@ -489,66 +768,76 @@ local function identify(prefix,reference) -- outer::inner var.kind = "outer with inner" end - var.i = { "reference", r } - jobreferences.resolvers.reference(var) - var.f = f + var.i = r + jobreferences.resolvers[r[1]](var) + var.f = outer end end end - if not r then - r = e.derived - if r then - r = r[prefix] - if r then - r = r[inner] - if r then - -- outer::inner - if arguments then - -- outer::inner{argument} - var.kind = "outer with inner with arguments" - else - -- outer::inner - var.kind = "outer with inner" - end - var.i = r - jobreferences.resolvers[r[1]](var) - var.f = f - end - end + end + if not r then + var.error = "unknown outer" + end + elseif special then + local s = specials[special] + if s then + if operation then + if arguments then + -- outer::special(operation{argument,argument}) + var.kind = "outer with special and operation and arguments" + else + -- outer::special(operation) + var.kind = "outer with special and operation" end + else + -- outer::special() + var.kind = "outer with special" end - if not r then - var.error = "unknown outer" - end - elseif special then - local s = specials[special] - if s then - if operation then - if arguments then - -- outer::special(operation{argument,argument}) - var.kind = "outer with special and operation and arguments" - else - -- outer::special(operation) - var.kind = "outer with special and operation" - end + var.f = outer + else + var.error = "unknown outer with special" + end + else + -- outer:: + var.kind = "outer" + var.f = outer + end + else + if inner then + if arguments then + -- outer::inner{argument} + var.kind = "outer with inner with arguments" + else + -- outer::inner + var.kind = "outer with inner" + end + var.i = { "reference", inner } + jobreferences.resolvers.reference(var) + var.f = outer + elseif special then + local s = specials[special] + if s then + if operation then + if arguments then + -- outer::special(operation{argument,argument}) + var.kind = "outer with special and operation and arguments" else - -- outer::special() - var.kind = "outer with special" + -- outer::special(operation) + var.kind = "outer with special and operation" end - var.f = f else - var.error = "unknown outer with special" + -- outer::special() + var.kind = "outer with special" end + var.f = outer else - -- outer:: - var.kind = "outer" - var.f = f + var.error = "unknown outer with special" end else - var.error = "unknown outer" + -- outer:: + var.kind = "outer" + var.f = outer end - else - var.error = "unknown outer" end else if arguments then @@ -611,6 +900,7 @@ local function identify(prefix,reference) set[i] = var end jobreferences.currentset = set +-- print(bug,table.serialize(set)) return set, bug end @@ -651,6 +941,36 @@ function jobreferences.setinternalreference(prefix,tag,internal,view) return destination end +function jobreferences.getinternalreference(n) -- n points into list + local l = structure.lists.collected[n] + texsprint(ctxcatcodes,(l and l.references.internal) or n) +end + + +-- + +function jobreferences.get_current_metadata(tag) + local data = currentreference and currentreference.i + data = data and data.metadata and data.metadata[tag] + if data then + texsprint(ctxcatcodes,data) + end +end +local function current_metadata(tag) + local data = currentreference and currentreference.i + return data and data.metadata and data.metadata[tag] +end +jobreferences.current_metadata = current_metadata + +function jobreferences.get_current_prefixspec(default) -- todo: message + texsprint(ctxcatcodes,"\\getreferencestructureprefix{", + current_metadata("kind") or "?", "}{", current_metadata("name") or "?", "}{", default or "?", "}") +end + +--~ function jobreferences.get_current_prefixspec(default) -- we can consider storing the data at the lua end +--~ context.getreferencestructureprefix(current_metadata("kind"),current_metadata("name"),default) +--~ end + -- jobreferences.filters = jobreferences.filters or { } @@ -659,23 +979,26 @@ local filters = jobreferences.filters local helpers = structure.helpers local sections = structure.sections -function jobreferences.filter(name) -- number page title ... +function jobreferences.filter(name,...) -- number page title ... local data = currentreference and currentreference.i if data then local kind = data.metadata and data.metadata.kind if kind then local filter = filters[kind] or filters.generic - filter = filter and (filter[name] or filters.generic[name]) + filter = filter and (filter[name] or filter.unknown or filters.generic[name] or filters.generic.unknown) if filter then - filter(data) + if trace_referencing then + logs.report("referencing","name '%s', kind '%s', using dedicated filter",name,kind) + end + filter(data,name,...) elseif trace_referencing then - logs.report("referencing","no (generic) filter.name for '%s'",name) + logs.report("referencing","name '%s', kind '%s', using generic filter",name,kind) end elseif trace_referencing then - logs.report("referencing","no metadata.kind for '%s'",name) + logs.report("referencing","name '%s', unknown kind",name) end elseif trace_referencing then - logs.report("referencing","no current reference for '%s'",name) + logs.report("referencing","name '%s', no reference",name) end end @@ -683,7 +1006,7 @@ filters.generic = { } function filters.generic.title(data) if data then - local titledata = data.titledata + local titledata = data.titledata or data.useddata if titledata then helpers.title(titledata.title or "?",data.metadata) end @@ -692,25 +1015,66 @@ end function filters.generic.text(data) if data then - local entries = data.entries + local entries = data.entries or data.useddata if entries then helpers.title(entries.text or "?",data.metadata) end end end -function filters.generic.number(data) -- todo: spec and then no stopper +function filters.generic.number(data,what,prefixspec) -- todo: spec and then no stopper if data then - helpers.prefix(data) local numberdata = data.numberdata if numberdata then - sections.typesetnumber(numberdata,"number",numberdata or false) +--~ print(table.serialize(prefixspec)) + helpers.prefix(data,prefixspec) + sections.typesetnumber(numberdata,"number",numberdata) + else + local useddata = data.useddata + if useddata and useddsta.number then + tex.sprint(tex.ctxcatcodes,useddata.number) + end end end end +filters.generic.default = filters.generic.text + function filters.generic.page(data,prefixspec,pagespec) - helpers.prefixpage(data,prefixspec,pagespec) + local pagedata = data.pagedata + if pagedata then -- imported + local number, conversion = pagedata.number, pagedata.conversion + if not number then + -- error + elseif conversion then + tex.sprint(tex.ctxcatcodes,format("\\convertnumber{%s}{%s}",conversion,number)) + else + tex.sprint(tex.ctxcatcodes,number) + end + else + helpers.prefixpage(data,prefixspec,pagespec) + end +end + +filters.user = { } + +function filters.user.unknown(data,name) + if data then + local userdata = data.userdata + local userkind = userdata and userdata.kind + if userkind then + local filter = filters[userkind] or filters.generic + filter = filter and (filter[name] or filter.unknown) + if filter then + filter(data,name) + return + end + end + local namedata = userdata and userdata[name] + if namedata then + texsprint(ctxcatcodes,namedata) + end + end end filters.text = { } @@ -731,23 +1095,29 @@ end filters.section = { } -filters.section.title = filters.generic.title -filters.section.page = filters.generic.page - -function filters.section.number(data) -- todo: spec and then no stopper +function filters.section.number(data,what,prefixspec) if data then local numberdata = data.numberdata if numberdata then - sections.typesetnumber(numberdata,"number",numberdata or false) + sections.typesetnumber(numberdata,"number",prefixspec,numberdata) + else + local useddata = data.useddata + if useddata and useddata.number then + tex.sprint(tex.ctxcatcodes,useddata.number) + end end end end ---~ filters.float = { } +filters.section.title = filters.generic.title +filters.section.page = filters.generic.page +filters.section.default = filters.section.number ---~ filters.float.title = filters.generic.title ---~ filters.float.number = filters.generic.number ---~ filters.float.page = filters.generic.page +filters.note = { default = filters.generic.number } +filters.formula = { default = filters.generic.number } +filters.float = { default = filters.generic.number } +filters.description = { default = filters.generic.number } +filters.item = { default = filters.generic.number } structure.references = structure.references or { } structure.helpers = structure.helpers or { } @@ -810,7 +1180,6 @@ function jobreferences.analyse(actions) return actions end - function jobreferences.realpage() -- special case, we always want result local cs = jobreferences.analyse() texwrite(cs.realpage or 0) @@ -863,7 +1232,7 @@ end specials.i = specials.internal -function specials.page(var,actions) +function specials.page(var,actions) -- is this ok? local p = pages[var.operation] if type(p) == "function" then p = p() |