summaryrefslogtreecommitdiff
path: root/tex/context/base/strc-num.lua
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/strc-num.lua')
-rw-r--r--tex/context/base/strc-num.lua207
1 files changed, 143 insertions, 64 deletions
diff --git a/tex/context/base/strc-num.lua b/tex/context/base/strc-num.lua
index 0715a9e49..b82132a00 100644
--- a/tex/context/base/strc-num.lua
+++ b/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 %q",tostring(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("saving, counter: %s, value: %s",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("synchronize, counter: %s, name: %s, value: %s, action: setting",dc,name,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("synchronize, counter: %s, name: %s, action: special",dc,name)
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("resetting, name: %s, sub: %s, value: %s",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("setting, name: %s, value: %s",name,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("checking, name: %s, sub: %s, value: %s",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("adding, name: %s, level: manually, action: no checking",name)
+ end
elseif level == -2 then
-- -2 is signal that we work per text
+ if trace_counters then
+ report_counters("adding, name: %s, level: text, action: checking",name)
+ 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("adding, name: %s, level: %s, action: checking within group",name,level)
+ end
check(name,data,n+1)
elseif level == 0 then
-- happens elsewhere
+ if trace_counters then
+ report_counters("adding, name: %s, level: %s, action: no checking",name,level)
+ end
+ else
+ if trace_counters then
+ report_counters("adding, name: %s, level: unknown, action: no checking",name)
+ 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("resetting, name: %s, level: %s (head)",name,level)
end
- counters.reset(name)
+ reset(name)
+ elseif cd.level == level then
+ if trace_counters then
+ report_counters("resetting, name: %s, level: %s (normal)",name,level)
+ 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
@@ -543,7 +622,7 @@ end
--~ return cd, false, "no section data"
--~ end
--~ -- local preferences
---~ local no = variables.no
+--~ local no = v_no
--~ if counterspecification and counterspecification.prefix == no then
--~ return cd, false, "current spec blocks prefix"
--~ end