summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/context/base/strc-ref.lua
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex/context/base/strc-ref.lua')
-rw-r--r--Master/texmf-dist/tex/context/base/strc-ref.lua849
1 files changed, 569 insertions, 280 deletions
diff --git a/Master/texmf-dist/tex/context/base/strc-ref.lua b/Master/texmf-dist/tex/context/base/strc-ref.lua
index 475ab318a8a..ee32353f0c4 100644
--- a/Master/texmf-dist/tex/context/base/strc-ref.lua
+++ b/Master/texmf-dist/tex/context/base/strc-ref.lua
@@ -7,14 +7,24 @@ if not modules then modules = { } end modules ['strc-ref'] = {
}
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 lpegmatch, lpegP, lpegCs = lpeg.match, lpeg.P, lpeg.Cs
+local texcount, texsetcount = tex.count, tex.setcount
+local rawget = rawget
-local trace_referencing = false trackers.register("structure.referencing", function(v) trace_referencing = v end)
+local allocate = utilities.storage.allocate
+local mark = utilities.storage.mark
+local setmetatableindex = table.setmetatableindex
+
+local trace_referencing = false trackers.register("structures.referencing", function(v) trace_referencing = v end)
+
+local report_references = logs.reporter("structure","references")
-local ctxcatcodes = tex.ctxcatcodes
local variables = interfaces.variables
local constants = interfaces.constants
+local context = context
+
+local settings_to_array = utilities.parsers.settings_to_array
+local unsetvalue = attributes.unsetvalue
-- 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
@@ -22,50 +32,119 @@ local constants = interfaces.constants
-- 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.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 = jobreferences.defined, jobreferences.derived, jobreferences.specials
-local exporters, runners = jobreferences.exporters, jobreferences.runners
+local structures = structures
+local helpers = structures.helpers
+local sections = structures.sections
+local references = structures.references
+local lists = structures.lists
+local counters = structures.counters
+
+-- some might become local
+
+references.defined = references.defined or allocate()
+
+local defined = references.defined
+local derived = allocate()
+local specials = allocate()
+local runners = allocate()
+local internals = allocate()
+local exporters = allocate()
+local imported = allocate()
+local filters = allocate()
+local executers = allocate()
+local handlers = allocate()
+local tobesaved = allocate()
+local collected = allocate()
+local tobereferred = allocate()
+local referred = allocate()
+
+references.derived = derived
+references.specials = specials
+references.runners = runners
+references.internals = internals
+references.exporters = exporters
+references.imported = imported
+references.filters = filters
+references.executers = executers
+references.handlers = handlers
+references.tobesaved = tobesaved
+references.collected = collected
+references.tobereferred = tobereferred
+references.referred = referred
+
+storage.register("structures/references/defined", references.defined, "structures.references.defined")
local currentreference = nil
local initializers = { }
local finalizers = { }
-function jobreferences.registerinitializer(func) -- we could use a token register instead
+function references.registerinitializer(func) -- we could use a token register instead
initializers[#initializers+1] = func
end
-function jobreferences.registerfinalizer(func) -- we could use a token register instead
+function references.registerfinalizer(func) -- we could use a token register instead
finalizers[#finalizers+1] = func
end
-local function initializer()
- tobesaved, collected = jobreferences.tobesaved, jobreferences.collected
+local function initializer() -- can we use a tobesaved as metatable for collected?
+ tobesaved = references.tobesaved
+ collected = references.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, finalizer)
+job.register('structures.references.collected', tobesaved, initializer, finalizer)
+
+local maxreferred = 1
+
+local function initializer() -- can we use a tobesaved as metatable for collected?
+ tobereferred = references.tobereferred
+ referred = references.referred
+ local function get(t,n) -- catch sparse, a bit slow but who cares
+ for i=n,1,-1 do -- we could make a tree ... too much work
+ local p = rawget(t,i)
+ if p then
+ return p
+ end
+ end
+ end
+ setmetatableindex(referred, get)
+end
+
+local function finalizer() -- make sparse
+ local last
+ for i=1,maxreferred do
+ local r = tobereferred[i]
+ if not last then
+ last = r
+ elseif r == last then
+ tobereferred[i] = nil
+ else
+ last = r
+ end
+ end
+end
+
+job.register('structures.references.referred', tobereferred, initializer, finalizer)
+
+function references.referredpage(n)
+ return referred[n] or referred[n] or texcount.realpageno
+end
+
+function references.registerpage(n)
+ if not tobereferred[n] then
+ if n > maxreferred then
+ maxreferred = n
+ end
+ tobereferred[n] = texcount.realpageno
+ end
end
-- todo: delay split till later as in destinations we split anyway
@@ -86,18 +165,18 @@ local function setnextorder(kind,name)
texsetcount("global","locationorder",lastorder)
end
-jobreferences.setnextorder = setnextorder
+references.setnextorder = setnextorder
-function jobreferences.setnextinternal(kind,name)
+function references.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)
+function references.currentorder(kind,name)
+ context(orders[kind] and orders[kind][name] or lastorder)
end
-function jobreferences.set(kind,prefix,tag,data)
+function references.set(kind,prefix,tag,data)
for ref in gmatch(tag,"[^,]+") do
local p, r = match(ref,"^(%-):(.-)$")
if p and r then
@@ -112,17 +191,17 @@ function jobreferences.set(kind,prefix,tag,data)
tobesaved[prefix] = pd
end
pd[ref] = data
- texsprint(ctxcatcodes,format("\\dofinish%sreference{%s}{%s}",kind,prefix,ref))
+ context.dofinishsomereference(kind,prefix,ref)
end
end
end
-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,nil,view) or -0x7FFFFFFF
+function references.setandgetattribute(kind,prefix,tag,data,view) -- maybe do internal automatically here
+ references.set(kind,prefix,tag,data)
+ texcount.lastdestinationattribute = references.setinternalreference(prefix,tag,nil,view) or -0x7FFFFFFF
end
-function jobreferences.enhance(prefix,tag,spec)
+function references.enhance(prefix,tag,spec)
local l = tobesaved[prefix][tag]
if l then
l.references.realpage = texcount.realpageno
@@ -133,9 +212,9 @@ end
local result = { }
-local lparent, rparent, lbrace, rbrace, dcolon, backslash = lpeg.P("("), lpeg.P(")"), lpeg.P("{"), lpeg.P("}"), lpeg.P("::"), lpeg.P("\\")
+local lparent, rparent, lbrace, rbrace, dcolon, backslash = lpegP("("), lpegP(")"), lpegP("{"), lpegP("}"), lpegP("::"), lpegP("\\")
-local reset = lpeg.P("") / function() result = { } end
+local reset = lpegP("") / function() result = { } end
local b_token = backslash / function(s) result.has_tex = true return s end
local o_token = 1 - rparent - rbrace - lparent - lbrace
@@ -144,11 +223,11 @@ local s_token = 1 - lparent - lbrace - lparent - lbrace
local i_token = 1 - lparent - lbrace
local f_token = 1 - lparent - lbrace - dcolon
-local outer = (f_token )^1 / function (s) result.outer = s end
-local operation = lpeg.Cs((b_token + o_token)^1) / function (s) result.operation = s end
-local arguments = lpeg.Cs((b_token + a_token)^0) / function (s) result.arguments = s end
-local special = (s_token )^1 / function (s) result.special = s end
-local inner = (i_token )^1 / function (s) result.inner = s end
+local outer = (f_token )^1 / function (s) result.outer = s end
+local operation = lpegCs((b_token + o_token)^1) / function (s) result.operation = s end
+local arguments = lpegCs((b_token + a_token)^0) / function (s) result.arguments = s end
+local special = (s_token )^1 / function (s) result.special = s end
+local inner = (i_token )^1 / function (s) result.inner = s end
local outer_reference = (outer * dcolon)^0
@@ -160,34 +239,34 @@ 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) -- overloaded
+--~ function references.analyze(str) -- overloaded
--~ return lpegmatch(scanner,str)
--~ end
-function jobreferences.split(str)
+function references.split(str)
return lpegmatch(scanner,str or "")
end
---~ print(table.serialize(jobreferences.analyse("")))
---~ print(table.serialize(jobreferences.analyse("inner")))
---~ print(table.serialize(jobreferences.analyse("special(operation{argument,argument})")))
---~ print(table.serialize(jobreferences.analyse("special(operation)")))
---~ print(table.serialize(jobreferences.analyse("special()")))
---~ print(table.serialize(jobreferences.analyse("inner{argument}")))
---~ print(table.serialize(jobreferences.analyse("outer::")))
---~ print(table.serialize(jobreferences.analyse("outer::inner")))
---~ print(table.serialize(jobreferences.analyse("outer::special(operation{argument,argument})")))
---~ print(table.serialize(jobreferences.analyse("outer::special(operation)")))
---~ print(table.serialize(jobreferences.analyse("outer::special()")))
---~ print(table.serialize(jobreferences.analyse("outer::inner{argument}")))
---~ print(table.serialize(jobreferences.analyse("special(outer::operation)")))
+--~ print(table.serialize(references.analyze("")))
+--~ print(table.serialize(references.analyze("inner")))
+--~ print(table.serialize(references.analyze("special(operation{argument,argument})")))
+--~ print(table.serialize(references.analyze("special(operation)")))
+--~ print(table.serialize(references.analyze("special()")))
+--~ print(table.serialize(references.analyze("inner{argument}")))
+--~ print(table.serialize(references.analyze("outer::")))
+--~ print(table.serialize(references.analyze("outer::inner")))
+--~ print(table.serialize(references.analyze("outer::special(operation{argument,argument})")))
+--~ print(table.serialize(references.analyze("outer::special(operation)")))
+--~ print(table.serialize(references.analyze("outer::special()")))
+--~ print(table.serialize(references.analyze("outer::inner{argument}")))
+--~ print(table.serialize(references.analyze("special(outer::operation)")))
-- -- -- related to strc-ini.lua -- -- --
-jobreferences.resolvers = jobreferences.resolvers or { }
+references.resolvers = references.resolvers or { }
-function jobreferences.resolvers.section(var)
- local vi = structure.lists.collected[var.i[2]]
+function references.resolvers.section(var)
+ local vi = lists.collected[var.i[2]]
if vi then
var.i = vi
var.r = (vi.references and vi.references.realpage) or (vi.pagedata and vi.pagedata.realpage) or 1
@@ -197,12 +276,12 @@ function jobreferences.resolvers.section(var)
end
end
-jobreferences.resolvers.float = jobreferences.resolvers.section
-jobreferences.resolvers.description = jobreferences.resolvers.section
-jobreferences.resolvers.formula = jobreferences.resolvers.section
-jobreferences.resolvers.note = jobreferences.resolvers.section
+references.resolvers.float = references.resolvers.section
+references.resolvers.description = references.resolvers.section
+references.resolvers.formula = references.resolvers.section
+references.resolvers.note = references.resolvers.section
-function jobreferences.resolvers.reference(var)
+function references.resolvers.reference(var)
local vi = var.i[2]
if vi then
var.i = vi
@@ -214,6 +293,7 @@ function jobreferences.resolvers.reference(var)
end
local function register_from_lists(collected,derived)
+ local g = derived[""] if not g then g = { } derived[""] = g end -- global
for i=1,#collected do
local entry = collected[i]
local m, r = entry.metadata, entry.references
@@ -226,9 +306,10 @@ local function register_from_lists(collected,derived)
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)
+ report_references("list entry %s provides %s reference '%s' on realpage %s",i,kind,s,realpage)
end
- d[s] = t -- share them
+ d[s] = d[s] or t -- share them
+ g[s] = g[s] or t -- first wins
end
end
end
@@ -236,30 +317,34 @@ local function register_from_lists(collected,derived)
end
end
-jobreferences.registerinitializer(function() register_from_lists(structure.lists.collected,derived) end)
+references.registerinitializer(function() register_from_lists(lists.collected,derived) end)
-- urls
-jobreferences.urls = jobreferences.urls or { }
-jobreferences.urls.data = jobreferences.urls.data or { }
+references.urls = references.urls or { }
+references.urls.data = references.urls.data or { }
-local urls = jobreferences.urls.data
+local urls = references.urls.data
-function jobreferences.urls.define(name,url,file,description)
+function references.urls.define(name,url,file,description)
if name and name ~= "" then
urls[name] = { url or "", file or "", description or url or file or ""}
end
end
-function jobreferences.urls.get(name,method,space) -- method: none, before, after, both, space: yes/no
+local pushcatcodes, popcatcodes, txtcatcodes = context.pushcatcodes, context.popcatcodes, tex.txtcatcodes
+
+function references.urls.get(name,method,space) -- method: none, before, after, both, space: yes/no
local u = urls[name]
if u then
local url, file = u[1], u[2]
+ pushcatcodes(txtcatcodes)
if file and file ~= "" then
- texsprint(ctxcatcodes,url,"/",file)
+ context("%s/%s",url,file)
else
- texsprint(ctxcatcodes,url)
+ context(url)
end
+ popcatcodes()
end
end
@@ -269,21 +354,21 @@ end
-- files
-jobreferences.files = jobreferences.files or { }
-jobreferences.files.data = jobreferences.files.data or { }
+references.files = references.files or { }
+references.files.data = references.files.data or { }
-local files = jobreferences.files.data
+local files = references.files.data
-function jobreferences.files.define(name,file,description)
+function references.files.define(name,file,description)
if name and name ~= "" then
files[name] = { file or "", description or file or ""}
end
end
-function jobreferences.files.get(name,method,space) -- method: none, before, after, both, space: yes/no
+function references.files.get(name,method,space) -- method: none, before, after, both, space: yes/no
local f = files[name]
if f then
- texsprint(ctxcatcodes,f[1])
+ context(f[1])
end
end
@@ -293,7 +378,7 @@ end
-- helpers
-function jobreferences.checkedfile(whatever) -- return whatever if not resolved
+function references.checkedfile(whatever) -- return whatever if not resolved
if whatever then
local w = files[whatever]
if w then
@@ -304,7 +389,7 @@ function jobreferences.checkedfile(whatever) -- return whatever if not resolved
end
end
-function jobreferences.checkedurl(whatever) -- return whatever if not resolved
+function references.checkedurl(whatever) -- return whatever if not resolved
if whatever then
local w = urls[whatever]
if w then
@@ -320,7 +405,7 @@ function jobreferences.checkedurl(whatever) -- return whatever if not resolved
end
end
-function jobreferences.checkedfileorurl(whatever,default) -- return nil, nil if not resolved
+function references.checkedfileorurl(whatever,default) -- return nil, nil if not resolved
if whatever then
local w = files[whatever]
if w then
@@ -342,25 +427,25 @@ end
-- programs
-jobreferences.programs = jobreferences.programs or { }
-jobreferences.programs.data = jobreferences.programs.data or { }
+references.programs = references.programs or { }
+references.programs.data = references.programs.data or { }
-local programs = jobreferences.programs.data
+local programs = references.programs.data
-function jobreferences.programs.define(name,file,description)
+function references.programs.define(name,file,description)
if name and name ~= "" then
programs[name] = { file or "", description or file or ""}
end
end
-function jobreferences.programs.get(name)
+function references.programs.get(name)
local f = programs[name]
if f then
- texsprint(ctxcatcodes,f[1])
+ context(f[1])
end
end
-function jobreferences.checkedprogram(whatever) -- return whatever if not resolved
+function references.checkedprogram(whatever) -- return whatever if not resolved
if whatever then
local w = programs[whatever]
if w then
@@ -373,36 +458,36 @@ 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)
+function references.whatfrom(name)
+ context((urls[name] and variables.url) or (files[name] and variables.file) or variables.unknown)
end
---~ function jobreferences.from(name)
+--~ function references.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))
+--~ context.dofromurldescription(description)
--~ -- ok
--~ elseif file and file ~= "" then
---~ texsprint(ctxcatcodes,format("\\dofromurlliteral{%s}",url .. "/" .. file))
+--~ context.dofromurlliteral(url .. "/" .. file)
--~ else
---~ texsprint(ctxcatcodes,format("\\dofromurlliteral{%s}",url))
+--~ context(dofromurlliteral,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))
+--~ context.dofromfiledescription(description)
--~ else
---~ texsprint(ctxcatcodes,format("\\dofromfileliteral{%s}",file))
+--~ context.dofromfileliteral(file)
--~ end
--~ end
--~ end
--~ end
-function jobreferences.from(name)
+function references.from(name)
local u = urls[name]
if u then
local url, file, description = u[1], u[2], u[3]
@@ -456,11 +541,12 @@ function exporters.lists.generic(data)
end
if numberdata then
local numbers = numberdata.numbers
- local t = { }
+ local t, tn = { }, 0
for i=1,#numbers do
local n = numbers[i]
if n ~= 0 then
- t[#t+1] = n
+ tn = tn + 1
+ t[tn] = n
end
end
useddata.number = concat(t,".")
@@ -481,13 +567,16 @@ local function referencer(data)
}
end
-function jobreferences.export(usedname)
+-- Exported and imported references ... not yet used but don't forget it
+-- and redo it.
+
+function references.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
+ for prefix, references in next, references.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
@@ -506,7 +595,7 @@ function jobreferences.export(usedname)
end
end
local pe = exported[""] if not pe then pe = { } exported[""] = pe end
- for n, data in next, structure.lists.tobesaved do
+ for n, data in next, lists.tobesaved do
local metadata = data.metadata
local exporter = e_lists[metadata.kind] or g_lists
if exporter then
@@ -531,9 +620,8 @@ function jobreferences.export(usedname)
io.savedata(file.replacesuffix(usedname or tex.jobname,"tue"),table.serialize(e,true))
end
-function jobreferences.import(usedname)
+function references.import(usedname)
if usedname then
- local imported = jobreferences.imported
local jdn = imported[usedname]
if not jdn then
local filename = files[usedname]
@@ -574,20 +662,20 @@ function jobreferences.import(usedname)
end
end
-function jobreferences.load(usedname)
+function references.load(usedname)
-- gone
end
-function jobreferences.define(prefix,reference,list)
+function references.define(prefix,reference,list)
local d = defined[prefix] if not d then d = { } defined[prefix] = d end
d[reference] = { "defined", list }
end
---~ function jobreferences.registerspecial(name,action,...)
+--~ function references.registerspecial(name,action,...)
--~ specials[name] = { action, ... }
--~ end
-function jobreferences.reset(prefix,reference)
+function references.reset(prefix,reference)
local d = defined[prefix]
if d then
d[reference] = nil
@@ -600,25 +688,55 @@ end
-- t.special t.operation t.arguments t.outer t.inner
-local settings_to_array = aux.settings_to_array
+-- to what extend do we check the non prefixed variant
+
+local strict = false
local function resolve(prefix,reference,args,set) -- we start with prefix,reference
texcount.referencehastexstate = 0
if reference and reference ~= "" then
- set = set or { }
+ if not set then
+ set = { prefix = prefix, reference = reference }
+ else
+ set.reference = set.reference or reference
+ set.prefix = set.prefix or prefix
+ end
local r = settings_to_array(reference)
for i=1,#r do
local ri = r[i]
- local dp = defined[prefix] or defined[""]
- local d = dp[ri]
+ local d
+ if strict then
+ d = defined[prefix] or defined[""]
+ d = d and d[ri]
+ else
+ d = defined[prefix]
+ d = d and d[ri]
+ if not d then
+ d = defined[""]
+ d = d and d[ri]
+ end
+ end
if d then
resolve(prefix,d[2],nil,set)
else
local var = lpegmatch(scanner,ri)
if var then
var.reference = ri
- if not var.outer and var.inner then
- local d = defined[prefix][var.inner] or defined[""][var.inner]
+ local vo, vi = var.outer, var.inner
+ if not vo and vi then
+ -- to be checked
+ if strict then
+ d = defined[prefix] or defined[""]
+ d = d and d[vi]
+ else
+ d = defined[prefix]
+ d = d and d[vi]
+ if not d then
+ d = defined[""]
+ d = d and d[vi]
+ end
+ end
+ --
if d then
resolve(prefix,d[2],var.arguments,set) -- args can be nil
else
@@ -633,13 +751,14 @@ local function resolve(prefix,reference,args,set) -- we start with prefix,refere
set.has_tex = true
end
else
- -- logs.report("references","funny pattern: %s",ri or "?")
+ -- report_references("funny pattern: %s",ri or "?")
end
end
end
if set.has_tex then
texcount.referencehastexstate = 1
end
+--~ table.print(set)
return set
else
return { }
@@ -648,41 +767,69 @@ end
-- prefix == "" is valid prefix which saves multistep lookup
-jobreferences.currentset = nil
+references.currentset = nil
+
+--~ local b, e = "\\ctxlua{local jc = structures.references.currentset;", "}"
+--~ local o, a = 'jc[%s].operation=[[%s]];', 'jc[%s].arguments=[[%s]];'
+--~
+--~ function references.expandcurrent() -- todo: two booleans: o_has_tex& a_has_tex
+--~ local currentset = references.currentset
+--~ if currentset and currentset.has_tex then
+--~ local done = false
+--~ for i=1,#currentset do
+--~ local ci = currentset[i]
+--~ local operation = ci.operation
+--~ if operation then
+--~ if find(operation,"\\") then -- if o_has_tex then
+--~ if not done then
+--~ context(b)
+--~ done = true
+--~ end
+--~ context(o,i,operation)
+--~ end
+--~ end
+--~ local arguments = ci.arguments
+--~ if arguments then
+--~ if find(arguments,"\\") then -- if a_has_tex then
+--~ if not done then
+--~ context(b)
+--~ done = true
+--~ end
+--~ context(a,i,arguments)
+--~ end
+--~ end
+--~ end
+--~ if done then
+--~ context(e)
+--~ end
+--~ end
+--~ end
+
+function commands.setreferenceoperation(k,v)
+ references.currentset[k].operation = v
+end
+
+function commands.setreferencearguments(k,v)
+ references.currentset[k].arguments = v
+end
-local b, e = "\\ctxlua{local jc = jobreferences.currentset;", "}"
-local o, a = 'jc[%s].operation=[[%s]];', 'jc[%s].arguments=[[%s]];'
+local expandreferenceoperation = context.expandreferenceoperation
+local expandreferencearguments = context.expandreferencearguments
-function jobreferences.expandcurrent() -- todo: two booleans: o_has_tex& a_has_tex
- local currentset = jobreferences.currentset
+function references.expandcurrent() -- todo: two booleans: o_has_tex& a_has_tex
+ local currentset = references.currentset
if currentset and currentset.has_tex then
- local done = false
for i=1,#currentset do
local ci = currentset[i]
local operation = ci.operation
- if operation then
- if find(operation,"\\") then -- if o_has_tex then
- if not done then
- texsprint(ctxcatcodes,b)
- done = true
- end
- texsprint(ctxcatcodes,format(o,i,operation))
- end
+ if operation and find(operation,"\\") then -- if o_has_tex then
+ expandreferenceoperation(i,operation)
end
local arguments = ci.arguments
- if arguments then
- if find(arguments,"\\") then -- if a_has_tex then
- if not done then
- texsprint(ctxcatcodes,b)
- done = true
- end
- texsprint(ctxcatcodes,format(a,i,arguments))
- end
+ if arguments and find(arguments,"\\") then -- if a_has_tex then
+ expandreferencearguments(i,arguments)
end
end
- if done then
- texsprint(ctxcatcodes,e)
- end
end
end
@@ -696,9 +843,17 @@ end
--~ end
--~ end
+local prefixsplitter = lpegCs(lpegP((1-lpegP(":"))^1 * lpegP(":"))) * lpegCs(lpegP(1)^1)
+
+-- todo: add lots of tracing here
+
+local n = 0
+
local function identify(prefix,reference)
local set = resolve(prefix,reference)
local bug = false
+n = n + 1
+set.n = n
for i=1,#set do
local var = set[i]
local special, inner, outer, arguments, operation = var.special, var.inner, var.outer, var.arguments, var.operation
@@ -730,7 +885,7 @@ local function identify(prefix,reference)
var.error = "unknown special"
end
elseif outer then
- local e = jobreferences.import(outer)
+ local e = references.import(outer)
if e then
if inner then
local r = e.references
@@ -747,7 +902,7 @@ local function identify(prefix,reference)
var.kind = "outer with inner"
end
var.i = { "reference", r }
- jobreferences.resolvers.reference(var)
+ references.resolvers.reference(var)
var.f = outer
var.e = true -- external
end
@@ -769,7 +924,7 @@ local function identify(prefix,reference)
var.kind = "outer with inner"
end
var.i = r
- jobreferences.resolvers[r[1]](var)
+ references.resolvers[r[1]](var)
var.f = outer
end
end
@@ -812,7 +967,7 @@ local function identify(prefix,reference)
var.kind = "outer with inner"
end
var.i = { "reference", inner }
- jobreferences.resolvers.reference(var)
+ references.resolvers.reference(var)
var.f = outer
elseif special then
local s = specials[special]
@@ -849,47 +1004,101 @@ local function identify(prefix,reference)
var.error = "unknown inner or special"
end
else
- -- inner
---~ local i = tobesaved[prefix]
- local i = collected[prefix]
- i = i and i[inner]
+ -- inner ... we could move the prefix logic into the parser so that we have 'm for each entry
+ -- foo:bar -> foo == prefix (first we try the global one)
+ -- -:bar -> ignore prefix
+ local p, i = prefix, nil
+ local splitprefix, splitinner = lpegmatch(prefixsplitter,inner)
+ -- these are taken from other anonymous references
+ if splitprefix and splitinner then
+ if splitprefix == "-" then
+ i = collected[""]
+ i = i and i[splitinner]
+ if i then
+ p = ""
+ end
+ else
+ i = collected[splitprefix]
+ i = i and i[splitinner]
+ if i then
+ p = splitprefix
+ end
+ end
+ end
+ -- todo: strict here
+ if not i then
+ i = collected[prefix]
+ i = i and i[inner]
+ if i then
+ p = prefix
+ end
+ end
+ if not i and prefix ~= "" then
+ i = collected[""]
+ i = i and i[inner]
+ if i then
+ p = ""
+ end
+ end
if i then
var.i = { "reference", i }
- jobreferences.resolvers.reference(var)
+ references.resolvers.reference(var)
var.kind = "inner"
- var.p = prefix
+ var.p = p
else
- i = derived[prefix]
- i = i and i[inner]
+ -- these are taken from other data structures (like lists)
+--~ print("!!!!!!!!!!!!!!",splitprefix,splitinner)
+--~ table.print(derived)
+ if splitprefix and splitinner then
+ if splitprefix == "-" then
+ i = derived[""]
+ i = i and i[splitinner]
+ if i then
+ p = ""
+ end
+ else
+ i = derived[splitprefix]
+ i = i and i[splitinner]
+ if i then
+ p = splitprefix
+ end
+ end
+ end
+ if not i then
+ i = derived[prefix]
+ i = i and i[inner]
+ if i then
+ p = prefix
+ end
+ end
+ if not i and prefix ~= "" then
+ i = derived[""]
+ i = i and i[inner]
+ if i then
+ p = ""
+ end
+ end
if i then
var.kind = "inner"
var.i = i
- jobreferences.resolvers[i[1]](var)
- var.p = prefix
+ references.resolvers[i[1]](var)
+ var.p = p
else
- i = collected[prefix]
- i = i and i[inner]
- if i then
- var.kind = "inner"
- var.i = { "reference", i }
- jobreferences.resolvers.reference(var)
- var.p = prefix
+ -- no prefixes here
+ local s = specials[inner]
+ if s then
+ var.kind = "special"
else
- local s = specials[inner]
- if s then
- var.kind = "special"
+ i = (collected[""] and collected[""][inner]) or
+ (derived [""] and derived [""][inner]) or
+ (tobesaved[""] and tobesaved[""][inner])
+ if i then
+ var.kind = "inner"
+ var.i = { "reference", i }
+ references.resolvers.reference(var)
+ var.p = ""
else
- i = (collected[""] and collected[""][inner]) or
- (derived [""] and derived [""][inner]) or
- (tobesaved[""] and tobesaved[""][inner])
- if i then
- var.kind = "inner"
- var.i = { "reference", i }
- jobreferences.resolvers.reference(var)
- var.p = ""
- else
- var.error = "unknown inner or special"
- end
+ var.error = "unknown inner or special"
end
end
end
@@ -899,87 +1108,131 @@ local function identify(prefix,reference)
bug = bug or var.error
set[i] = var
end
- jobreferences.currentset = set
--- print(bug,table.serialize(set))
+ references.currentset = mark(set) -- mark, else in api doc
+--~ table.print(set,tostring(bug))
return set, bug
end
-jobreferences.identify = identify
+references.identify = identify
-function jobreferences.doifelse(prefix,reference,highlight,newwindow,layer)
+local unknowns, nofunknowns = { }, 0
+
+function references.doifelse(prefix,reference,highlight,newwindow,layer)
local set, bug = identify(prefix,reference)
local unknown = bug or #set == 0
if unknown then
currentreference = nil -- will go away
+ local str = format("[%s][%s]",prefix,reference)
+ local u = unknowns[str]
+ if not u then
+ interfaces.showmessage("references",1,str) -- 1 = unknown, 4 = illegal
+ unknowns[str] = 1
+ nofunknowns = nofunknowns + 1
+ else
+ unknowns[str] = u + 1
+ end
else
set.highlight, set.newwindow,set.layer = highlight, newwindow, layer
currentreference = set[1]
end
-- we can do the expansion here which saves a call
+--~ print("!!!!!!",not unknown)
commands.doifelse(not unknown)
end
-function jobreferences.setinternalreference(prefix,tag,internal,view)
- local t = { }
- if tag then
- if prefix and prefix ~= "" then
- prefix = prefix .. ":"
- for ref in gmatch(tag,"[^,]+") do
- t[#t+1] = prefix .. ref
- end
- else
- for ref in gmatch(tag,"[^,]+") do
- t[#t+1] = ref
- end
+function references.reportproblems() -- might become local
+ if nofunknowns > 0 then
+ interfaces.showmessage("references",5,nofunknowns) -- 5 = unknown, 6 = illegal
+ -- -- we need a proper logger specific for the log file
+ -- texio.write_nl("log",format("%s unknown references",nofunknowns))
+ -- for k, v in table.sortedpairs(unknowns) do
+ -- texio.write_nl("log",format("%s (n=%s)",k,v))
+ -- end
+ -- texio.write_nl("log","")
+ end
+end
+
+luatex.registerstopactions(references.reportproblems)
+
+local innermethod = "names"
+
+function references.setinnermethod(m)
+ if m then
+ if m == "page" or m == "mixed" or m == "names" then
+ innermethod = m
+ elseif m == true or m == variables.yes then
+ innermethod = "page"
end
end
- if internal then
- t[#t+1] = "aut:" .. internal
+ function references.setinnermethod()
+ report_references("inner method is already set and frozen to '%s'",innermethod)
end
- local destination = jobreferences.mark(t,nil,nil,view) -- returns an attribute
- texcount.lastdestinationattribute = destination
- 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)
+function references.getinnermethod()
+ return innermethod or "names"
+end
+
+directives.register("references.linkmethod", function(v) -- page mixed names
+ references.setinnermethod(v)
+end)
+
+function references.setinternalreference(prefix,tag,internal,view)
+ if innermethod == "page" then
+ return unsetvalue
+ else
+ local t, tn = { }, 0 -- maybe add to current
+ if tag then
+ if prefix and prefix ~= "" then
+ prefix = prefix .. ":"
+ for ref in gmatch(tag,"[^,]+") do
+ tn = tn + 1
+ t[tn] = prefix .. ref
+ end
+ else
+ for ref in gmatch(tag,"[^,]+") do
+ tn = tn + 1
+ t[tn] = ref
+ end
+ end
+ end
+ if internal and innermethod == "names" then -- mixed or page
+ tn = tn + 1
+ t[tn] = "aut:" .. internal
+ end
+ local destination = references.mark(t,nil,nil,view) -- returns an attribute
+ texcount.lastdestinationattribute = destination
+ return destination
+ end
end
+function references.getinternalreference(n) -- n points into list (todo: registers)
+ local l = lists.collected[n]
+ context(l and l.references.internal or n)
+end
--
-function jobreferences.get_current_metadata(tag)
+function references.getcurrentmetadata(tag)
local data = currentreference and currentreference.i
data = data and data.metadata and data.metadata[tag]
if data then
- texsprint(ctxcatcodes,data)
+ context(data)
end
end
-local function current_metadata(tag)
+
+local function currentmetadata(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
+references.currentmetadata = currentmetadata
---
-
-jobreferences.filters = jobreferences.filters or { }
-
-local filters = jobreferences.filters
-local helpers = structure.helpers
-local sections = structure.sections
+function references.getcurrentprefixspec(default) -- todo: message
+ context.getreferencestructureprefix(currentmetadata("kind") or "?",currentmetadata("name") or "?",default or "?")
+end
-function jobreferences.filter(name,...) -- number page title ...
+function references.filter(name,...) -- number page title ...
local data = currentreference and currentreference.i
if data then
local kind = data.metadata and data.metadata.kind
@@ -988,17 +1241,17 @@ function jobreferences.filter(name,...) -- number page title ...
filter = filter and (filter[name] or filter.unknown or filters.generic[name] or filters.generic.unknown)
if filter then
if trace_referencing then
- logs.report("referencing","name '%s', kind '%s', using dedicated filter",name,kind)
+ report_references("name '%s', kind '%s', using dedicated filter",name,kind)
end
filter(data,name,...)
elseif trace_referencing then
- logs.report("referencing","name '%s', kind '%s', using generic filter",name,kind)
+ report_references("name '%s', kind '%s', using generic filter",name,kind)
end
elseif trace_referencing then
- logs.report("referencing","name '%s', unknown kind",name)
+ report_references("name '%s', unknown kind",name)
end
elseif trace_referencing then
- logs.report("referencing","name '%s', no reference",name)
+ report_references("name '%s', no reference",name)
end
end
@@ -1032,7 +1285,7 @@ function filters.generic.number(data,what,prefixspec) -- todo: spec and then no
else
local useddata = data.useddata
if useddata and useddsta.number then
- tex.sprint(tex.ctxcatcodes,useddata.number)
+ context(useddata.number)
end
end
end
@@ -1047,9 +1300,9 @@ function filters.generic.page(data,prefixspec,pagespec)
if not number then
-- error
elseif conversion then
- tex.sprint(tex.ctxcatcodes,format("\\convertnumber{%s}{%s}",conversion,number))
+ context.convertnumber(conversion,number)
else
- tex.sprint(tex.ctxcatcodes,number)
+ context(number)
end
else
helpers.prefixpage(data,prefixspec,pagespec)
@@ -1072,7 +1325,7 @@ function filters.user.unknown(data,name)
end
local namedata = userdata and userdata[name]
if namedata then
- texsprint(ctxcatcodes,namedata)
+ context(namedata)
end
end
end
@@ -1080,12 +1333,10 @@ end
filters.text = { }
function filters.text.title(data)
--- texsprint(ctxcatcodes,"[text title]")
helpers.title(data.entries.text or "?",data.metadata)
end
function filters.text.number(data)
--- texsprint(ctxcatcodes,"[text number]")
helpers.title(data.entries.text or "?",data.metadata)
end
@@ -1103,7 +1354,7 @@ function filters.section.number(data,what,prefixspec)
else
local useddata = data.useddata
if useddata and useddata.number then
- tex.sprint(tex.ctxcatcodes,useddata.number)
+ context(useddata.number)
end
end
end
@@ -1119,12 +1370,6 @@ 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 { }
-
-local references = structure.references
-local helpers = structure.helpers
-
function references.sectiontitle(n)
helpers.sectiontitle(lists.collected[tonumber(n) or 0])
end
@@ -1137,25 +1382,39 @@ function references.sectionpage(n,prefixspec,pagespec)
helpers.prefixedpage(lists.collected[tonumber(n) or 0],prefixspec,pagespec)
end
--- analyse
+-- analyze
-jobreferences.testrunners = jobreferences.testrunners or { }
-jobreferences.testspecials = jobreferences.testspecials or { }
+references.testrunners = references.testrunners or { }
+references.testspecials = references.testspecials or { }
-local runners = jobreferences.testrunners
-local specials = jobreferences.testspecials
+local runners = references.testrunners
+local specials = references.testspecials
-function jobreferences.analyse(actions)
- actions = actions or jobreferences.currentset
+local function checkedpagestate(n,page)
+ local r, p = referred[n] or texcount.realpageno, tonumber(page)
+ if not p then
+ return 0
+ elseif p > r then
+ return 3
+ elseif p < r then
+ return 2
+ else
+ return 1
+ end
+end
+
+function references.analyze(actions)
+ actions = actions or references.currentset
if not actions then
actions = { realpage = 0 }
+ texcount.referencepagestate = 0
elseif actions.realpage then
- -- already analysed
+ -- already analyzed
+ texcount.referencepagestate = checkedpagestate(actions.n,actions.realpage)
else
-- we store some analysis data alongside the indexed array
- -- at this moment only the real reference page is analysed
+ -- at this moment only the real reference page is analyzed
-- normally such an analysis happens in the backend code
- texcount.referencepagestate = 0
local nofactions = #actions
if nofactions > 0 then
for i=1,nofactions do
@@ -1165,43 +1424,53 @@ function jobreferences.analyse(actions)
what = what(a,actions)
end
end
- local realpage, p = texcount.realpageno, tonumber(actions.realpage)
- if not p then
- -- sorry
- elseif p > realpage then
- texcount.referencepagestate = 3
- elseif p < realpage then
- texcount.referencepagestate = 2
- else
- texcount.referencepagestate = 1
- end
+ texcount.referencepagestate = checkedpagestate(actions.n,actions.realpage)
+ else
+ texcount.referencepagestate = 0
end
end
return actions
end
-function jobreferences.realpage() -- special case, we always want result
- local cs = jobreferences.analyse()
- texwrite(cs.realpage or 0)
+function references.realpage() -- special case, we always want result
+ local cs = references.analyze()
+ context(cs.realpage or 0)
end
+local plist
+
+local function realpageofpage(p)
+ if not plist then
+ local pages = structures.pages.collected
+ plist = { }
+ for rp=1,#pages do
+ plist[pages[rp].number] = rp
+ end
+ end
+ return plist[p]
+end
+
+references.realpageofpage = realpageofpage
+
--
-jobreferences.pages = {
- [variables.firstpage] = function() return structure.counters.record("realpage")["first"] end,
- [variables.previouspage] = function() return structure.counters.record("realpage")["previous"] end,
- [variables.nextpage] = function() return structure.counters.record("realpage")["next"] end,
- [variables.lastpage] = function() return structure.counters.record("realpage")["last"] end,
+local pages = allocate {
+ [variables.firstpage] = function() return counters.record("realpage")["first"] end,
+ [variables.previouspage] = function() return counters.record("realpage")["previous"] end,
+ [variables.nextpage] = function() return counters.record("realpage")["next"] end,
+ [variables.lastpage] = function() return counters.record("realpage")["last"] end,
- [variables.firstsubpage] = function() return structure.counters.record("subpage" )["first"] end,
- [variables.previoussubpage] = function() return structure.counters.record("subpage" )["previous"] end,
- [variables.nextsubpage] = function() return structure.counters.record("subpage" )["next"] end,
- [variables.lastsubpage] = function() return structure.counters.record("subpage" )["last"] end,
+ [variables.firstsubpage] = function() return counters.record("subpage" )["first"] end,
+ [variables.previoussubpage] = function() return counters.record("subpage" )["previous"] end,
+ [variables.nextsubpage] = function() return counters.record("subpage" )["next"] end,
+ [variables.lastsubpage] = function() return counters.record("subpage" )["last"] end,
- [variables.forward] = function() return structure.counters.record("realpage")["forward"] end,
- [variables.backward] = function() return structure.counters.record("realpage")["backward"] end,
+ [variables.forward] = function() return counters.record("realpage")["forward"] end,
+ [variables.backward] = function() return counters.record("realpage")["backward"] end,
}
+references.pages = pages
+
-- maybe some day i will merge this in the backend code with a testmode (so each
-- runner then implements a branch)
@@ -1220,10 +1489,10 @@ end
runners["special operation"] = runners["special"]
runners["special operation with arguments"] = runners["special"]
-local pages = jobreferences.pages
+-- weird, why is this code here and in lpdf-ano
function specials.internal(var,actions)
- local v = jobreferences.internals[tonumber(var.operation)]
+ local v = references.internals[tonumber(var.operation)]
local r = v and v.references.realpage
if r then
actions.realpage = r
@@ -1232,12 +1501,32 @@ end
specials.i = specials.internal
-function specials.page(var,actions) -- is this ok?
- local p = pages[var.operation]
+function specials.page(var,actions)
+ local o = var.operation
+ local p = pages[o]
if type(p) == "function" then
p = p()
+ else
+ p = tonumber(realpageofpage(tonumber(o)))
+ end
+ if p then
+ var.r = p
+ actions.realpage = actions.realpage or p -- first wins
end
+end
+
+function specials.realpage(var,actions)
+ local p = tonumber(var.operation)
+ if p then
+ var.r = p
+ actions.realpage = actions.realpage or p -- first wins
+ end
+end
+
+function specials.userpage(var,actions)
+ local p = tonumber(realpageofpage(var.operation))
if p then
- actions.realpage = p
+ var.r = p
+ actions.realpage = actions.realpage or p -- first wins
end
end