diff options
Diffstat (limited to 'Master/texmf-dist/tex/context/base/strc-num.lua')
-rw-r--r-- | Master/texmf-dist/tex/context/base/strc-num.lua | 307 |
1 files changed, 193 insertions, 114 deletions
diff --git a/Master/texmf-dist/tex/context/base/strc-num.lua b/Master/texmf-dist/tex/context/base/strc-num.lua index 0715a9e4913..b0eae6b78bb 100644 --- a/Master/texmf-dist/tex/context/base/strc-num.lua +++ b/Master/texmf-dist/tex/context/base/strc-num.lua @@ -6,12 +6,13 @@ if not modules then modules = { } end modules ['strc-num'] = { license = "see context related readme files" } --- this will be reimplemented and some more will move to the commands namespace - local format = string.format local next, type = next, type local min, max = math.min, math.max -local texcount = tex.count +local texcount, texsetcount = tex.count, tex.setcount + +-- Counters are managed here. They can have multiple levels which makes it easier to synchronize +-- them. Synchronization is sort of special anyway, as it relates to document structuring. local allocate = utilities.storage.allocate local setmetatableindex = table.setmetatableindex @@ -26,8 +27,23 @@ local counters = structures.counters local documents = structures.documents local variables = interfaces.variables - --- state: start stop none reset +local v_start = variables.start +local v_page = variables.page +local v_reverse = variables.reverse +local v_first = variables.first +local v_next = variables.next +local v_previous = variables.previous +local v_prev = variables.prev +local v_last = variables.last +----- v_no = variables.no +local v_backward = variables.backward +local v_forward = variables.forward +----- v_subs = variables.subs or "subs" + +-- states: start stop none reset + +-- specials are used for counters that are set and incremented in special ways, like +-- pagecounters that get this treatment in the page builder counters.specials = counters.specials or { } local counterspecials = counters.specials @@ -66,54 +82,83 @@ end job.register('structures.counters.collected', tobesaved, initializer, finalizer) -local function constructor(t,s,name,i) -- variables ? - if s == "last" then +local constructor = { -- maybe some day we will provide an installer for more variants + + last = function(t,name,i) local cc = collected[name] - t.stop = (cc and cc[i] and cc[i][t.range]) or 0 -- stop is available for diagnostics purposes only + local stop = (cc and cc[i] and cc[i][t.range]) or 0 -- stop is available for diagnostics purposes only + t.stop = stop if t.offset then - return t.stop - t.step + return stop - t.step else - return t.stop + return stop end - elseif s == "first" then - if t.start > 0 then - return t.start -- brrr + end, + + first = function(t,name,i) + local start = t.start + if start > 0 then + return start -- brrr elseif t.offset then - return t.start + t.step + 1 + return start + t.step + 1 else - return t.start + 1 + return start + 1 end - elseif s == "prev" or s == "previous" then + end, + + prev = function(t,name,i) return max(t.first,t.number-1) -- todo: step - elseif s == "next" then + end, + + previous = function(t,name,i) + return max(t.first,t.number-1) -- todo: step + end, + + next = function(t,name,i) return min(t.last,t.number+1) -- todo: step - elseif s == "backward" then + end, + + backward =function(t,name,i) if t.number - 1 < t.first then return t.last else return t.previous end - elseif s == "forward" then + end, + + forward = function(t,name,i) if t.number + 1 > t.last then return t.first else return t.next end - elseif s == "subs" then + end, + + subs = function(t,name,i) local cc = collected[name] t.subs = (cc and cc[i+1] and cc[i+1][t.range]) or 0 return t.subs - else - return nil -- was 0, but that is fuzzy in testing for e.g. own - end + end, + +} + +local function dummyconstructor(t,name,i) + return nil -- was 0, but that is fuzzy in testing for e.g. own end +setmetatableindex(constructor,function(t,k) + if trace_counters then + report_counters("unknown constructor %a",k) + end + return dummyconstructor +end) + local function enhance() for name, cd in next, counterdata do local data = cd.data for i=1,#data do local ci = data[i] - setmetatableindex(ci, function(t,s) return constructor(t,s,name,i) end) + setmetatableindex(ci, function(t,s) return constructor[s](t,name,i) end) end end enhance = nil @@ -126,7 +171,7 @@ local function allocate(name,i) -- can be metatable level = 1, -- block = "", -- todo numbers = nil, - state = variables.start, -- true + state = v_start, -- true data = { }, saved = { }, } @@ -145,7 +190,7 @@ local function allocate(name,i) -- can be metatable offset = false, stop = 0, -- via metatable: last, first, stop only for tracing } - setmetatableindex(ci, function(t,s) return constructor(t,s,name,i) end) + setmetatableindex(ci, function(t,s) return constructor[s](t,name,i) end) cd[i] = ci tobesaved[name][i] = { } else @@ -164,12 +209,12 @@ local function savevalue(name,i) local cs = tobesaved[name][i] local cc = collected[name] if trace_counters then - report_counters("saving value %s of counter named %s",cd.number,name) + report_counters("action %a, counter %s, value %s","save",name,cd.number) end local cr = cd.range local old = (cc and cc[i] and cc[i][cr]) or 0 local number = cd.number - if cd.method == variables.page then + if cd.method == v_page then -- we can be one page ahead number = number - 1 end @@ -186,8 +231,8 @@ function counters.define(specification) if name and name ~= "" then -- todo: step local d = allocate(name,1) - d.start = specification.start - d.state = variables.start or "" + d.start = tonumber(specification.start) or 0 + d.state = v_state or "" local counter = specification.counter if counter and counter ~= "" then d.counter = counter -- only for special purposes, cannot be false @@ -202,18 +247,15 @@ end function counters.compact(name,level,onlynumbers) local cd = counterdata[name] ---~ print(name,cd) if cd then local data = cd.data local compact = { } for i=1,level or #data do local d = data[i] ---~ print(name,i,d.number) if d.number ~= 0 then compact[i] = (onlynumbers and d.number) or d end end ---~ print(table.serialize(compact)) return compact end end @@ -246,65 +288,76 @@ function counters.subs(name,n) return counterdata[name].data[n].subs or 0 end -function counters.setvalue(name,tag,value) +local function setvalue(name,tag,value) local cd = counterdata[name] if cd then cd[tag] = value end end +counters.setvalue = setvalue + function counters.setstate(name,value) -- true/false value = variables[value] if value then - counters.setvalue(name,"state",value) + setvalue(name,"state",value) end end function counters.setlevel(name,value) - counters.setvalue(name,"level",value) + setvalue(name,"level",value) end function counters.setoffset(name,value) - counters.setvalue(name,"offset",value) + setvalue(name,"offset",value) end local function synchronize(name,d) local dc = d.counter if dc then if trace_counters then - report_counters("setting counter %s with name %s to %s",dc,name,d.number) + report_counters("action %a, name %a, counter %a, value %a","synchronize",name,dc,d.number) end - tex.setcount("global",dc,d.number) + texsetcount("global",dc,d.number) end local cs = counterspecials[name] if cs then if trace_counters then - report_counters("invoking special for name %s",name) + report_counters("action %a, name %a, counter %a","synccommand",name,dc) end - cs() + cs(name) end end -function counters.reset(name,n) +local function reset(name,n) local cd = counterdata[name] if cd then for i=n or 1,#cd.data do local d = cd.data[i] savevalue(name,i) - d.number = d.start or 0 + local number = d.start or 0 + d.number = number d.own = nil + if trace_counters then + report_counters("action %a, name %a, sub %a, value %a","reset",name,i,number) + end synchronize(name,d) end cd.numbers = nil + else end end -function counters.set(name,n,value) +local function set(name,n,value) local cd = counterdata[name] if cd then local d = allocate(name,n) - d.number = value or 0 + local number = value or 0 + d.number = number d.own = nil + if trace_counters then + report_counters("action %a, name %a, sub %a, value %a","set",name,"no",number) + end synchronize(name,d) end end @@ -313,12 +366,19 @@ local function check(name,data,start,stop) for i=start or 1,stop or #data do local d = data[i] savevalue(name,i) - d.number = d.start or 0 + local number = d.start or 0 + d.number = number d.own = nil + if trace_counters then + report_counters("action %a, name %a, sub %a, value %a","check",name,i,number) + end synchronize(name,d) end end +counters.reset = reset +counters.set = set + function counters.setown(name,n,value) local cd = counterdata[name] if cd then @@ -328,7 +388,7 @@ function counters.setown(name,n,value) local level = cd.level if not level or level == -1 then -- -1 is signal that we reset manually - elseif level > 0 then + elseif level > 0 or level == -3 then check(name,d,n+1) elseif level == 0 then -- happens elsewhere, check this for block @@ -345,7 +405,7 @@ function counters.restart(name,n,newstart,noreset) local d = allocate(name,n) d.start = newstart if not noreset then - counters.reset(name,n) -- hm + reset(name,n) -- hm end end end @@ -367,24 +427,38 @@ end function counters.add(name,n,delta) local cd = counterdata[name] --- inspect(cd) - if cd and (cd.state == variables.start or cd.state == "") then + if cd and (cd.state == v_start or cd.state == "") then local data = cd.data local d = allocate(name,n) d.number = (d.number or d.start or 0) + delta*(d.step or 0) -- d.own = nil local level = cd.level --- print(name,n,delta,level) if not level or level == -1 then -- -1 is signal that we reset manually + if trace_counters then + report_counters("action %a, name %a, sub %a, how %a","add",name,"no","no checking") + end elseif level == -2 then -- -2 is signal that we work per text + if trace_counters then + report_counters("action %a, name %a, sub %a, how %a","add",name,"text","checking") + end check(name,data,n+1) - elseif level > 0 then + elseif level > 0 or level == -3 then -- within countergroup + if trace_counters then + report_counters("action %a, name %a, sub %a, how %a","add",name,level,"checking within group") + end check(name,data,n+1) elseif level == 0 then -- happens elsewhere + if trace_counters then + report_counters("action %a, name %a, sub %a, how %a","add",name,level,"no checking") + end + else + if trace_counters then + report_counters("action %a, name %a, sub %a, how %a","add",name,"unknown","no checking") + end end synchronize(name,d) return d.number -- not needed @@ -392,19 +466,23 @@ function counters.add(name,n,delta) return 0 end -function counters.check(level) -- not used (yet) +function counters.check(level) for name, cd in next, counterdata do - -- report_counters("%s %s %s",name,cd.level,level) - if cd.level == level then + if level > 0 and cd.level == -3 then -- could become an option if trace_counters then - report_counters("resetting %s at level %s",name,level) + report_counters("action %a, name %a, sub %a, detail %a","reset",name,level,"head") end - counters.reset(name) + reset(name) + elseif cd.level == level then + if trace_counters then + report_counters("action %a, name %a, sub %a, detail %a","reset",name,level,"normal") + end + reset(name) end end end -function counters.get(name,n,key) +local function get(name,n,key) local d = allocate(name,n) d = d and d[key] if not d then @@ -416,8 +494,10 @@ function counters.get(name,n,key) end end +counters.get = get + function counters.value(name,n) -- what to do with own - return counters.get(name,n or 1,'number') or 0 + return get(name,n or 1,'number') or 0 end function counters.converted(name,spec) -- name can be number and reference to storage @@ -431,9 +511,8 @@ function counters.converted(name,spec) -- name can be number and reference to st if cd then local spec = spec or { } local numbers, ownnumbers = { }, { } - local reverse = spec.order == variables.reverse + local reverse = spec.order == v_reverse local kind = spec.type or "number" - local v_first, v_next, v_previous, v_last = variables.first, variables.next, variables.previous, variables.last local data = cd.data for k=1,#data do local v = data[k] @@ -446,7 +525,7 @@ function counters.converted(name,spec) -- name can be number and reference to st vn = v.first elseif kind == v_next then vn = v.next - elseif kind == v_previous then + elseif kind == v_prev or kind == v_previous then vn = v.prev elseif kind == v_last then vn = v.last @@ -498,7 +577,7 @@ function commands.showcounter(name) local data = cd.data for i=1,#data do local d = data[i] - context(" (%s: %s,%s,%s s:%s r:%s)",i,(d.start or 0),d.number or 0,d.last,d.step or 0,d.range or 0) + context(" (%s: %s,%s,%s s:%s r:%s)",i,d.start or 0,d.number or 0,d.last,d.step or 0,d.range or 0) end context("]") end @@ -517,54 +596,54 @@ function commands.checkcountersetup(name,level,start,state) sections.setchecker(name,level,counters.reset) end ---~ -- move to strc-pag.lua - ---~ function counters.analyze(name,counterspecification) ---~ local cd = counterdata[name] ---~ -- safeguard ---~ if not cd then ---~ return false, false, "no counter data" ---~ end ---~ -- section data ---~ local sectiondata = sections.current() ---~ if not sectiondata then ---~ return cd, false, "not in section" ---~ end ---~ local references = sectiondata.references ---~ if not references then ---~ return cd, false, "no references" ---~ end ---~ local section = references.section ---~ if not section then ---~ return cd, false, "no section" ---~ end ---~ sectiondata = sections.collected[references.section] ---~ if not sectiondata then ---~ return cd, false, "no section data" ---~ end ---~ -- local preferences ---~ local no = variables.no ---~ if counterspecification and counterspecification.prefix == no then ---~ return cd, false, "current spec blocks prefix" ---~ end ---~ -- stored preferences (not used) ---~ if cd.prefix == no then ---~ return cd, false, "entry blocks prefix" ---~ end ---~ -- sectioning ---~ -- if sectiondata.prefix == no then ---~ -- return false, false, "sectiondata blocks prefix" ---~ -- end ---~ -- final verdict ---~ return cd, sectiondata, "okay" ---~ end - ---~ function counters.prefixedconverted(name,prefixspec,numberspec) ---~ local cd, prefixdata, result = counters.analyze(name,prefixspec) ---~ if cd then ---~ if prefixdata then ---~ sections.typesetnumber(prefixdata,"prefix",prefixspec or false,cd or false) ---~ end ---~ counters.converted(name,numberspec) ---~ end ---~ end +-- -- move to strc-pag.lua +-- +-- function counters.analyze(name,counterspecification) +-- local cd = counterdata[name] +-- -- safeguard +-- if not cd then +-- return false, false, "no counter data" +-- end +-- -- section data +-- local sectiondata = sections.current() +-- if not sectiondata then +-- return cd, false, "not in section" +-- end +-- local references = sectiondata.references +-- if not references then +-- return cd, false, "no references" +-- end +-- local section = references.section +-- if not section then +-- return cd, false, "no section" +-- end +-- sectiondata = sections.collected[references.section] +-- if not sectiondata then +-- return cd, false, "no section data" +-- end +-- -- local preferences +-- local no = v_no +-- if counterspecification and counterspecification.prefix == no then +-- return cd, false, "current spec blocks prefix" +-- end +-- -- stored preferences (not used) +-- if cd.prefix == no then +-- return cd, false, "entry blocks prefix" +-- end +-- -- sectioning +-- -- if sectiondata.prefix == no then +-- -- return false, false, "sectiondata blocks prefix" +-- -- end +-- -- final verdict +-- return cd, sectiondata, "okay" +-- end +-- +-- function counters.prefixedconverted(name,prefixspec,numberspec) +-- local cd, prefixdata, result = counters.analyze(name,prefixspec) +-- if cd then +-- if prefixdata then +-- sections.typesetnumber(prefixdata,"prefix",prefixspec or false,cd or false) +-- end +-- counters.converted(name,numberspec) +-- end +-- end |