summaryrefslogtreecommitdiff
path: root/tex/context/base/strc-doc.lua
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/strc-doc.lua')
-rw-r--r--tex/context/base/strc-doc.lua1912
1 files changed, 956 insertions, 956 deletions
diff --git a/tex/context/base/strc-doc.lua b/tex/context/base/strc-doc.lua
index 50a9e67a0..37a16c414 100644
--- a/tex/context/base/strc-doc.lua
+++ b/tex/context/base/strc-doc.lua
@@ -1,956 +1,956 @@
-if not modules then modules = { } end modules ['strc-doc'] = {
- version = 1.001,
- comment = "companion to strc-doc.mkiv",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
--- todo: associate counter with head
--- we need to better split the lua/tex end
--- we need to freeze and document this module
-
--- keep this as is:
---
--- in section titles by default a zero aborts, so there we need: sectionset=bagger with \definestructureprefixset [bagger] [section-2,section-4] []
--- in lists however zero's are ignored, so there numbersegments=2:4 gives result
-
-local next, type, tonumber, select = next, type, tonumber, select
-local format, gsub, find, gmatch, match = string.format, string.gsub, string.find, string.gmatch, string.match
-local concat, fastcopy = table.concat, table.fastcopy
-local max, min = math.max, math.min
-local allocate, mark, accesstable = utilities.storage.allocate, utilities.storage.mark, utilities.tables.accesstable
-local setmetatableindex = table.setmetatableindex
-
-local catcodenumbers = catcodes.numbers
-local ctxcatcodes = catcodenumbers.ctxcatcodes
-local variables = interfaces.variables
-
-local v_last = variables.last
-local v_first = variables.first
-local v_previous = variables.previous
-local v_next = variables.next
-local v_auto = variables.auto
-local v_strict = variables.strict
-local v_all = variables.all
-local v_positive = variables.positive
-local v_by = variables.by
-
-local trace_sectioning = false trackers.register("structures.sectioning", function(v) trace_sectioning = v end)
-local trace_detail = false trackers.register("structures.detail", function(v) trace_detail = v end)
-
-local report_structure = logs.reporter("structure","sectioning")
-
-local structures = structures
-local context = context
-
-local helpers = structures.helpers
-local documents = structures.documents
-local sections = structures.sections
-local lists = structures.lists
-local counters = structures.counters
-local sets = structures.sets
-local tags = structures.tags
-
-local processors = typesetters.processors
-local applyprocessor = processors.apply
-local startapplyprocessor = processors.startapply
-local stopapplyprocessor = processors.stopapply
-local strippedprocessor = processors.stripped
-
-local a_internal = attributes.private('internal')
-
--- -- -- document -- -- --
-
-local data -- the current state
-
-function documents.initialize()
- data = allocate { -- whole data is marked
- numbers = { },
- forced = { },
- ownnumbers = { },
- status = { },
- checkers = { },
- depth = 0,
- blocks = { },
- block = "",
- }
- documents.data = data
-end
-
-function documents.reset()
- data.numbers = { }
- data.forced = { }
- data.ownnumbers = { }
- data.status = { }
- -- data.checkers = { }
- data.depth = 0
-end
-
-documents.initialize()
-
--- -- -- components -- -- --
-
-function documents.preset(numbers)
- local nofnumbers = #numbers
- local ownnumbers = { }
- data.numbers = numbers
- data.ownnumbers = ownnumbers
- data.depth = nofnumbers
- for i=1,nofnumbers do
- ownnumbers[i] = ""
- end
- sections.setnumber(nofnumbers,"-1")
-end
-
--- -- -- sections -- -- --
-
-local collected = allocate()
-local tobesaved = allocate()
-
-sections.collected = collected
-sections.tobesaved = tobesaved
-
--- local function initializer()
--- collected = sections.collected
--- tobesaved = sections.tobesaved
--- end
---
--- job.register('structures.sections.collected', tobesaved, initializer)
-
-sections.registered = sections.registered or allocate()
-local registered = sections.registered
-
-storage.register("structures/sections/registered", registered, "structures.sections.registered")
-
-function sections.register(name,specification)
- registered[name] = specification
-end
-
-function sections.currentid()
- return #tobesaved
-end
-
-function sections.save(sectiondata)
--- local sectionnumber = helpers.simplify(section.sectiondata) -- maybe done earlier
- local numberdata = sectiondata.numberdata
- local ntobesaved = #tobesaved
- if not numberdata or sectiondata.metadata.nolist then
- return ntobesaved
- else
- ntobesaved = ntobesaved + 1
- tobesaved[ntobesaved] = numberdata
- if not collected[ntobesaved] then
- collected[ntobesaved] = numberdata
- end
- return ntobesaved
- end
-end
-
-function sections.load()
- setmetatableindex(collected,nil)
- local lists = lists.collected
- for i=1,#lists do
- local list = lists[i]
- local metadata = list.metadata
- if metadata and metadata.kind == "section" and not metadata.nolist then
- local numberdata = list.numberdata
- if numberdata then
- collected[#collected+1] = numberdata
- end
- end
- end
- sections.load = functions.dummy
-end
-
-table.setmetatableindex(collected, function(t,i)
- sections.load()
- return collected[i] or { }
-end)
-
---
-
-sections.levelmap = sections.levelmap or { }
-
-local levelmap = sections.levelmap
-
-storage.register("structures/sections/levelmap", sections.levelmap, "structures.sections.levelmap")
-
-sections.verbose = true
-
-levelmap.block = -1
-
-function sections.setlevel(name,level) -- level can be number or parent (=string)
- local l = tonumber(level)
- if not l then
- l = levelmap[level]
- end
- if l and l > 0 then
- levelmap[name] = l
- else
- -- error
- end
-end
-
-function sections.getlevel(name)
- return levelmap[name] or 0
-end
-
-function sections.setblock(name)
- local block = name or data.block or "unknown" -- can be used to set the default
- data.block = block
- return block
-end
-
-function sections.pushblock(name)
- counters.check(0) -- we assume sane usage of \page between blocks
- local block = name or data.block
- data.blocks[#data.blocks+1] = block
- data.block = block
- documents.reset()
- return block
-end
-
-function sections.popblock()
- data.blocks[#data.blocks] = nil
- local block = data.blocks[#data.blocks] or data.block
- data.block = block
- documents.reset()
- return block
-end
-
-function sections.currentblock()
- return data.block or data.blocks[#data.blocks] or "unknown"
-end
-
-function sections.currentlevel()
- return data.depth
-end
-
-function sections.getcurrentlevel()
- context(data.depth)
-end
-
-local saveset = { } -- experiment, see sections/tricky-001.tex
-
-function sections.somelevel(given)
- -- old number
- local numbers = data.numbers
-
- local ownnumbers = data.ownnumbers
- local forced = data.forced
- local status = data.status
- local olddepth = data.depth
- local givenname = given.metadata.name
- local mappedlevel = levelmap[givenname]
- local newdepth = tonumber(mappedlevel or (olddepth > 0 and olddepth) or 1) -- hm, levelmap only works for section-*
- local directives = given.directives
- local resetset = directives and directives.resetset or ""
- -- local resetter = sets.getall("structure:resets",data.block,resetset)
- -- a trick to permit userdata to overload title, ownnumber and reference
- -- normally these are passed as argument but nowadays we provide several
- -- interfaces (we need this because we want to be compatible)
- if trace_detail then
- report_structure("name %a, mapped level %a, old depth %a, new depth %a, reset set %a",
- givenname,mappedlevel,olddepth,newdepth,resetset)
- end
- local u = given.userdata
- if u then
- -- kind of obsolete as we can pass them directly anyway
- if u.reference and u.reference ~= "" then given.metadata.reference = u.reference ; u.reference = nil end
- if u.ownnumber and u.ownnumber ~= "" then given.numberdata.ownnumber = u.ownnumber ; u.ownnumber = nil end
- if u.title and u.title ~= "" then given.titledata.title = u.title ; u.title = nil end
- if u.bookmark and u.bookmark ~= "" then given.titledata.bookmark = u.bookmark ; u.bookmark = nil end
- if u.label and u.label ~= "" then given.titledata.label = u.label ; u.label = nil end
- end
- -- so far for the trick
- if saveset then
- saveset[newdepth] = (resetset ~= "" and resetset) or saveset[newdepth] or ""
- end
- if newdepth > olddepth then
- for i=olddepth+1,newdepth do
- local s = tonumber(sets.get("structure:resets",data.block,saveset and saveset[i] or resetset,i))
- if trace_detail then
- report_structure("new depth %s, old depth %s, reset set %a, reset value %a, current %a",olddepth,newdepth,resetset,s,numbers[i])
- end
- if not s or s == 0 then
- numbers[i] = numbers[i] or 0
- ownnumbers[i] = ownnumbers[i] or ""
- else
- numbers[i] = s - 1
- ownnumbers[i] = ""
- end
- status[i] = { }
- end
- elseif newdepth < olddepth then
- for i=olddepth,newdepth+1,-1 do
- local s = tonumber(sets.get("structure:resets",data.block,saveset and saveset[i] or resetset,i))
- if trace_detail then
- report_structure("new depth %s, old depth %s, reset set %a, reset value %a, current %a",olddepth,newdepth,resetset,s,numbers[i])
- end
- if not s or s == 0 then
- numbers[i] = numbers[i] or 0
- ownnumbers[i] = ownnumbers[i] or ""
- else
- numbers[i] = s - 1
- ownnumbers[i] = ""
- end
- status[i] = nil
- end
- end
- counters.check(newdepth)
- ownnumbers[newdepth] = given.numberdata.ownnumber or ""
- given.numberdata.ownnumber = nil
- data.depth = newdepth
- -- new number
- olddepth = newdepth
- if given.metadata.increment then
- local oldn, newn = numbers[newdepth] or 0, 0
- local fd = forced[newdepth]
- if fd then
- if fd[1] == "add" then
- newn = oldn + fd[2] + 1
- else
- newn = fd[2] + 1
- end
- if newn < 0 then
- newn = 1 -- maybe zero is nicer
- end
- forced[newdepth] = nil
- if trace_detail then
- report_structure("old depth %a, new depth %a, old n %a, new n %a, forced %t",olddepth,newdepth,oldn,newn,fd)
- end
- else
- newn = oldn + 1
- if trace_detail then
- report_structure("old depth %a, new depth %a, old n %a, new n %a, increment",olddepth,newdepth,oldn,newn)
- end
- end
- numbers[newdepth] = newn
- end
- status[newdepth] = given or { }
- for k, v in next, data.checkers do
- if v[1] == newdepth and v[2] then
- v[2](k)
- end
- end
- local numberdata= given.numberdata
- if not numberdata then
- -- probably simplified to nothing
- numberdata = { }
- given.numberdata = numberdata
- end
-
- local n = { }
- for i=1,newdepth do
- n[i] = numbers[i]
- end
- numberdata.numbers = n
--- numberdata.numbers = fastcopy(numbers)
-
- if #ownnumbers > 0 then
- numberdata.ownnumbers = fastcopy(ownnumbers)
- end
- if trace_detail then
- report_structure("name %a, numbers % a, own numbers % a",givenname,numberdata.numbers,numberdata.ownnumbers)
- end
-
- local metadata = given.metadata
- local references = given.references
-
- local tag = references.tag or tags.getid(metadata.kind,metadata.name)
- if tag and tag ~= "" and tag ~= "?" then
- references.tag = tag
- end
-
- local setcomponent = structures.references.setcomponent
- if setcomponent then
- setcomponent(given) -- might move to the tex end
- end
-
- references.section = sections.save(given)
- -- given.numberdata = nil
-end
-
-function sections.reportstructure()
- if sections.verbose then
- local numbers, ownnumbers, status, depth = data.numbers, data.ownnumbers, data.status, data.depth
- local d = status[depth]
- local o = concat(ownnumbers,".",1,depth)
- local n = (numbers and concat(numbers,".",1,min(depth,#numbers))) or 0
- local l = d.titledata.title or ""
- local t = (l ~= "" and l) or d.titledata.title or "[no title]"
- local m = d.metadata.name
- if o and not find(o,"^%.*$") then
- report_structure("%s @ level %i : (%s) %s -> %s",m,depth,n,o,t)
- elseif d.directives and d.directives.hidenumber then
- report_structure("%s @ level %i : (%s) -> %s",m,depth,n,t)
- else
- report_structure("%s @ level %i : %s -> %s",m,depth,n,t)
- end
- end
-end
-
-function sections.setnumber(depth,n)
- local forced, depth, new = data.forced, depth or data.depth, tonumber(n)
- if type(n) == "string" then
- if find(n,"^[%+%-]") then
- forced[depth] = { "add", new }
- else
- forced[depth] = { "set", new }
- end
- else
- forced[depth] = { "set", new }
- end
-end
-
-function sections.numberatdepth(depth)
- return data.numbers[tonumber(depth) or sections.getlevel(depth) or 0] or 0
-end
-
-function sections.numbers()
- return data.numbers
-end
-
-function sections.matchingtilldepth(depth,numbers,parentnumbers)
- local dn = parentnumbers or data.numbers
- local ok = false
- for i=1,depth do
- if dn[i] == numbers[i] then
- ok = true
- else
- return false
- end
- end
- return ok
-end
-
-function sections.getnumber(depth) -- redefined later ...
- context(data.numbers[depth] or 0)
-end
-
-function sections.set(key,value)
- data.status[data.depth][key] = value -- may be nil for a reset
-end
-
-function sections.cct()
- local metadata = data.status[data.depth].metadata
- context(metadata and metadata.catcodes or ctxcatcodes)
-end
-
--- this one will become: return catcode, d (etc)
-
-function sections.structuredata(depth,key,default,honorcatcodetable) -- todo: spec table and then also depth
- if depth then
- depth = levelmap[depth] or tonumber(depth)
- end
- if not depth or depth == 0 then
- depth = data.depth
- end
- local data = data.status[depth]
- local d
- if data then
- if find(key,"%.") then
- d = accesstable(key,data)
- else
- d = data.titledata
- d = d and d[key]
- end
- end
- if d and type(d) ~= "table" then
- if honorcatcodetable == true or honorcatcodetable == v_auto then
- local metadata = data.metadata
- local catcodes = metadata and metadata.catcodes
- if catcodes then
- context.sprint(catcodes,d)
- else
- context(d)
- end
- elseif not honorcatcodetable or honorcatcodetable == "" then
- context(d)
- else
- local catcodes = catcodenumbers[honorcatcodetable]
- if catcodes then
- context.sprint(catcodes,d)
- else
- context(d)
- end
- end
- elseif default then
- context(default)
- end
-end
-
-function sections.userdata(depth,key,default)
- if depth then
- depth = levelmap[depth] or tonumber(depth)
- end
- if not depth or depth == 0 then
- depth = data.depth
- end
- if depth > 0 then
- local userdata = data.status[depth]
- userdata = userdata and userdata.userdata
- userdata = (userdata and userdata[key]) or default
- if userdata then
- context(userdata)
- end
- end
-end
-
-function sections.setchecker(name,level,command) -- hm, checkers are not saved
- data.checkers[name] = (name and command and level >= 0 and { level, command }) or nil
-end
-
-function sections.current()
- return data.status[data.depth]
-end
-
-function sections.depthnumber(n)
- local depth = data.depth
- if not n or n == 0 then
- n = depth
- elseif n < 0 then
- n = depth + n
- end
- return context(data.numbers[n] or 0)
-end
-
-function sections.autodepth(numbers)
- for i=#numbers,1,-1 do
- if numbers[i] ~= 0 then
- return i
- end
- end
- return 0
-end
-
---
-
-function structures.currentsectionnumber() -- brr, namespace wrong
- local sc = sections.current()
- return sc and sc.numberdata
-end
-
--- \dorecurse{3} {
--- \chapter{Blabla} \subsection{bla 1 1} \subsection{bla 1 2}
--- \section{bla 2} \subsection{bla 2 1} \subsection{bla 2 2}
--- }
-
--- sign=all => also zero and negative
--- sign=positive => also zero
--- sign=hang => llap sign
-
---~ todo: test this
---~
-
-local function process(index,numbers,ownnumbers,criterium,separatorset,conversion,conversionset,index,entry,result,preceding,done)
- -- todo: too much (100 steps)
- local number = numbers and (numbers[index] or 0)
- local ownnumber = ownnumbers and ownnumbers[index] or ""
- if number > criterium or (ownnumber ~= "") then
- local block = (entry.block ~= "" and entry.block) or sections.currentblock() -- added
- if preceding then
- local separator = sets.get("structure:separators",block,separatorset,preceding,".")
- if separator then
- if result then
- result[#result+1] = strippedprocessor(separator)
- else
- applyprocessor(separator)
- end
- end
- preceding = false
- end
- if result then
- if ownnumber ~= "" then
- result[#result+1] = ownnumber
- elseif conversion and conversion ~= "" then -- traditional (e.g. used in itemgroups) .. inherited!
- result[#result+1] = converters.convert(conversion,number)
- else
- local theconversion = sets.get("structure:conversions",block,conversionset,index,"numbers")
- result[#result+1] = converters.convert(theconversion,number)
- end
- else
- if ownnumber ~= "" then
- applyprocessor(ownnumber)
- elseif conversion and conversion ~= "" then -- traditional (e.g. used in itemgroups)
- context.convertnumber(conversion,number)
- else
- local theconversion = sets.get("structure:conversions",block,conversionset,index,"numbers")
- local data = startapplyprocessor(theconversion)
- context.convertnumber(data or "numbers",number)
- stopapplyprocessor()
- end
- end
- return index, true
- else
- return preceding or false, done
- end
-end
-
-function sections.typesetnumber(entry,kind,...) -- kind='section','number','prefix'
- if entry and entry.hidenumber ~= true then -- can be nil
- local separatorset = ""
- local conversionset = ""
- local conversion = ""
- local groupsuffix = ""
- local stopper = ""
- local starter = ""
- local connector = ""
- local set = ""
- local segments = ""
- local criterium = ""
- for d=1,select("#",...) do
- local data = select(d,...) -- can be multiple parametersets
- if data then
- if separatorset == "" then separatorset = data.separatorset or "" end
- if conversionset == "" then conversionset = data.conversionset or "" end
- if conversion == "" then conversion = data.conversion or "" end
- if groupsuffix == "" then groupsuffix = data.groupsuffix or "" end
- if stopper == "" then stopper = data.stopper or "" end
- if starter == "" then starter = data.starter or "" end
- if connector == "" then connector = data.connector or "" end
- if set == "" then set = data.set or "" end
- if segments == "" then segments = data.segments or "" end
- if criterium == "" then criterium = data.criterium or "" end
- end
- end
- if separatorset == "" then separatorset = "default" end
- if conversionset == "" then conversionset = "default" end -- not used
- if conversion == "" then conversion = nil end
- if groupsuffix == "" then groupsuffix = nil end
- if stopper == "" then stopper = nil end
- if starter == "" then starter = nil end
- if connector == "" then connector = nil end
- if set == "" then set = "default" end
- if segments == "" then segments = nil end
- --
- if criterium == v_strict then
- criterium = 0
- elseif criterium == v_positive then
- criterium = -1
- elseif criterium == v_all then
- criterium = -1000000
- else
- criterium = 0
- end
- --
- local firstprefix, lastprefix = 0, 16
- if segments then
- local f, l = match(tostring(segments),"^(.-):(.+)$")
- if l == "*" then
- l = 100 -- new
- end
- if f and l then
- -- 0:100, chapter:subsubsection
- firstprefix = tonumber(f) or sections.getlevel(f) or 0
- lastprefix = tonumber(l) or sections.getlevel(l) or 100
- else
- -- 3, section
- local fl = tonumber(segments) or sections.getlevel(segments) -- generalize
- if fl then
- firstprefix = fl
- lastprefix = fl
- end
- end
- end
- --
- local numbers, ownnumbers = entry.numbers, entry.ownnumbers
- if numbers then
- local done, preceding = false, false
- --
- local result = kind == "direct" and { }
- if result then
- connector = false
- end
- --
- local prefixlist = set and sets.getall("structure:prefixes","",set) -- "" == block
- if starter then
- if result then
- result[#result+1] = strippedprocessor(starter)
- else
- applyprocessor(starter)
- end
- end
- if prefixlist and (kind == 'section' or kind == 'prefix' or kind == 'direct') then
- -- find valid set (problem: for sectionnumber we should pass the level)
- -- no holes
- local b, e, bb, ee = 1, #prefixlist, 0, 0
- -- find last valid number
- for k=e,b,-1 do
- local prefix = prefixlist[k]
- local index = sections.getlevel(prefix) or k
- if index >= firstprefix and index <= lastprefix then
- local number = numbers and numbers[index]
- if number then
- local ownnumber = ownnumbers and ownnumbers[index] or ""
- if number > 0 or (ownnumber ~= "") then
- break
- else
- e = k -1
- end
- end
- end
- end
- -- find valid range
- for k=b,e do
- local prefix = prefixlist[k]
- local index = sections.getlevel(prefix) or k
- if index >= firstprefix and index <= lastprefix then
- local number = numbers and numbers[index]
- if number then
- local ownnumber = ownnumbers and ownnumbers[index] or ""
- if number > 0 or (ownnumber ~= "") then
- if bb == 0 then bb = k end
- ee = k
- else
- bb, ee = 0, 0
- end
- else
- break
- end
- end
- end
- -- print valid range
- for k=bb,ee do
- local prefix = prefixlist[k]
- local index = sections.getlevel(prefix) or k
- if index >= firstprefix and index <= lastprefix then
- -- process(index,result)
- preceding, done = process(index,numbers,ownnumbers,criterium,separatorset,conversion,conversionset,index,entry,result,preceding,done)
- end
- end
- else
- -- also holes check
- for index=firstprefix,lastprefix do
- -- process(index,result)
- preceding, done = process(index,numbers,ownnumbers,criterium,separatorset,conversion,conversionset,index,entry,result,preceding,done)
- end
- end
- --
- if done then
- if connector and kind == 'prefix' then
- if result then
- -- can't happen as we're in 'direct'
- else
- applyprocessor(connector)
- end
- else
-if groupsuffix and kind ~= "prefix" then
- if result then
- result[#result+1] = strippedprocessor(groupsuffix)
- else
- applyprocessor(groupsuffix)
- end
-end
- if stopper then
- if result then
- result[#result+1] = strippedprocessor(stopper)
- else
- applyprocessor(stopper)
- end
- end
- end
- end
- return result -- a table !
- else
- -- report_structure("error: no numbers")
- end
- end
-end
-
-function sections.title()
- local sc = sections.current()
- if sc then
- helpers.title(sc.titledata.title,sc.metadata)
- end
-end
-
-function sections.findnumber(depth,what) -- needs checking (looks wrong and slow too)
- local data = data.status[depth or data.depth]
- if data then
- local index = data.references.section
- local collected = sections.collected
- local sectiondata = collected[index]
- if sectiondata and sectiondata.hidenumber ~= true then -- can be nil
- local quit = what == v_previous or what == v_next
- if what == v_first or what == v_previous then
- for i=index,1,-1 do
- local s = collected[i]
- if s then
- local n = s.numbers
- if #n == depth and n[depth] and n[depth] ~= 0 then
- sectiondata = s
- if quit then
- break
- end
- elseif #n < depth then
- break
- end
- end
- end
- elseif what == v_last or what == v_next then
- for i=index,#collected do
- local s = collected[i]
- if s then
- local n = s.numbers
- if #n == depth and n[depth] and n[depth] ~= 0 then
- sectiondata = s
- if quit then
- break
- end
- elseif #n < depth then
- break
- end
- end
- end
- end
- return sectiondata
- end
- end
-end
-
-function sections.finddata(depth,what)
- local data = data.status[depth or data.depth]
- if data then
- -- if sectiondata and sectiondata.hidenumber ~= true then -- can be nil
- local index = data.references.listindex
- if index then
- local collected = structures.lists.collected
- local quit = what == v_previous or what == v_next
- if what == v_first or what == v_previous then
- for i=index-1,1,-1 do
- local s = collected[i]
- if not s then
- break
- elseif s.metadata.kind == "section" then -- maybe check on name
- local n = s.numberdata.numbers
- if #n == depth and n[depth] and n[depth] ~= 0 then
- data = s
- if quit then
- break
- end
- elseif #n < depth then
- break
- end
- end
- end
- elseif what == v_last or what == v_next then
- for i=index+1,#collected do
- local s = collected[i]
- if not s then
- break
- elseif s.metadata.kind == "section" then -- maybe check on name
- local n = s.numberdata.numbers
- if #n == depth and n[depth] and n[depth] ~= 0 then
- data = s
- if quit then
- break
- end
- elseif #n < depth then
- break
- end
- end
- end
- end
- end
- return data
- end
-end
-
-function sections.internalreference(sectionname,what) -- to be used in pagebuilder (no marks used)
- local r = type(sectionname) == "number" and sectionname or registered[sectionname]
- if r then
- local data = sections.finddata(r.level,what)
- return data and data.references and data.references.internal
- end
-end
-
-function sections.fullnumber(depth,what)
- local sectiondata = sections.findnumber(depth,what)
- if sectiondata then
- sections.typesetnumber(sectiondata,'section',sectiondata)
- end
-end
-
-function sections.getnumber(depth,what) -- redefined here
- local sectiondata = sections.findnumber(depth,what)
- context((sectiondata and sectiondata.numbers[depth]) or 0)
-end
-
--- experimental
-
-local levels = { }
-
---~ function commands.autonextstructurelevel(level)
---~ if level > #levels then
---~ for i=#levels+1,level do
---~ levels[i] = ""
---~ end
---~ end
---~ local finish = concat(levels,"\n",level) or ""
---~ for i=level+1,#levels do
---~ levels[i] = ""
---~ end
---~ levels[level] = [[\finalizeautostructurelevel]]
---~ context(finish)
---~ end
-
---~ function commands.autofinishstructurelevels()
---~ local finish = concat(levels,"\n") or ""
---~ levels = { }
---~ context(finish)
---~ end
-
-function commands.autonextstructurelevel(level)
- if level > #levels then
- for i=#levels+1,level do
- levels[i] = false
- end
- else
- for i=level,#levels do
- if levels[i] then
- context.finalizeautostructurelevel()
- levels[i] = false
- end
- end
- end
- levels[level] = true
-end
-
-function commands.autofinishstructurelevels()
- for i=1,#levels do
- if levels[i] then
- context.finalizeautostructurelevel()
- end
- end
- levels = { }
-end
-
--- interface (some are actually already commands, like sections.fullnumber)
-
-commands.structurenumber = function() sections.fullnumber() end
-commands.structuretitle = function() sections.title () end
-
-commands.structurevariable = function(name) sections.structuredata(nil,name) end
-commands.structureuservariable = function(name) sections.userdata (nil,name) end
-commands.structurecatcodedget = function(name) sections.structuredata(nil,name,nil,true) end
-commands.structuregivencatcodedget = function(name,catcode) sections.structuredata(nil,name,nil,catcode) end
-commands.structureautocatcodedget = function(name,catcode) sections.structuredata(nil,name,nil,catcode) end
-
-commands.namedstructurevariable = function(depth,name) sections.structuredata(depth,name) end
-commands.namedstructureuservariable = function(depth,name) sections.userdata (depth,name) end
-
---
-
-function commands.setsectionblock (name) context(sections.setblock(name)) end
-function commands.pushsectionblock(name) context(sections.pushblock(name)) end
-function commands.popsectionblock () context(sections.popblock()) end
-
---
-
-local byway = "^" .. v_by -- ugly but downward compatible
-
-function commands.way(way)
- context((gsub(way,byway,"")))
-end
+if not modules then modules = { } end modules ['strc-doc'] = {
+ version = 1.001,
+ comment = "companion to strc-doc.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- todo: associate counter with head
+-- we need to better split the lua/tex end
+-- we need to freeze and document this module
+
+-- keep this as is:
+--
+-- in section titles by default a zero aborts, so there we need: sectionset=bagger with \definestructureprefixset [bagger] [section-2,section-4] []
+-- in lists however zero's are ignored, so there numbersegments=2:4 gives result
+
+local next, type, tonumber, select = next, type, tonumber, select
+local format, gsub, find, gmatch, match = string.format, string.gsub, string.find, string.gmatch, string.match
+local concat, fastcopy = table.concat, table.fastcopy
+local max, min = math.max, math.min
+local allocate, mark, accesstable = utilities.storage.allocate, utilities.storage.mark, utilities.tables.accesstable
+local setmetatableindex = table.setmetatableindex
+
+local catcodenumbers = catcodes.numbers
+local ctxcatcodes = catcodenumbers.ctxcatcodes
+local variables = interfaces.variables
+
+local v_last = variables.last
+local v_first = variables.first
+local v_previous = variables.previous
+local v_next = variables.next
+local v_auto = variables.auto
+local v_strict = variables.strict
+local v_all = variables.all
+local v_positive = variables.positive
+local v_by = variables.by
+
+local trace_sectioning = false trackers.register("structures.sectioning", function(v) trace_sectioning = v end)
+local trace_detail = false trackers.register("structures.detail", function(v) trace_detail = v end)
+
+local report_structure = logs.reporter("structure","sectioning")
+
+local structures = structures
+local context = context
+
+local helpers = structures.helpers
+local documents = structures.documents
+local sections = structures.sections
+local lists = structures.lists
+local counters = structures.counters
+local sets = structures.sets
+local tags = structures.tags
+
+local processors = typesetters.processors
+local applyprocessor = processors.apply
+local startapplyprocessor = processors.startapply
+local stopapplyprocessor = processors.stopapply
+local strippedprocessor = processors.stripped
+
+local a_internal = attributes.private('internal')
+
+-- -- -- document -- -- --
+
+local data -- the current state
+
+function documents.initialize()
+ data = allocate { -- whole data is marked
+ numbers = { },
+ forced = { },
+ ownnumbers = { },
+ status = { },
+ checkers = { },
+ depth = 0,
+ blocks = { },
+ block = "",
+ }
+ documents.data = data
+end
+
+function documents.reset()
+ data.numbers = { }
+ data.forced = { }
+ data.ownnumbers = { }
+ data.status = { }
+ -- data.checkers = { }
+ data.depth = 0
+end
+
+documents.initialize()
+
+-- -- -- components -- -- --
+
+function documents.preset(numbers)
+ local nofnumbers = #numbers
+ local ownnumbers = { }
+ data.numbers = numbers
+ data.ownnumbers = ownnumbers
+ data.depth = nofnumbers
+ for i=1,nofnumbers do
+ ownnumbers[i] = ""
+ end
+ sections.setnumber(nofnumbers,"-1")
+end
+
+-- -- -- sections -- -- --
+
+local collected = allocate()
+local tobesaved = allocate()
+
+sections.collected = collected
+sections.tobesaved = tobesaved
+
+-- local function initializer()
+-- collected = sections.collected
+-- tobesaved = sections.tobesaved
+-- end
+--
+-- job.register('structures.sections.collected', tobesaved, initializer)
+
+sections.registered = sections.registered or allocate()
+local registered = sections.registered
+
+storage.register("structures/sections/registered", registered, "structures.sections.registered")
+
+function sections.register(name,specification)
+ registered[name] = specification
+end
+
+function sections.currentid()
+ return #tobesaved
+end
+
+function sections.save(sectiondata)
+-- local sectionnumber = helpers.simplify(section.sectiondata) -- maybe done earlier
+ local numberdata = sectiondata.numberdata
+ local ntobesaved = #tobesaved
+ if not numberdata or sectiondata.metadata.nolist then
+ return ntobesaved
+ else
+ ntobesaved = ntobesaved + 1
+ tobesaved[ntobesaved] = numberdata
+ if not collected[ntobesaved] then
+ collected[ntobesaved] = numberdata
+ end
+ return ntobesaved
+ end
+end
+
+function sections.load()
+ setmetatableindex(collected,nil)
+ local lists = lists.collected
+ for i=1,#lists do
+ local list = lists[i]
+ local metadata = list.metadata
+ if metadata and metadata.kind == "section" and not metadata.nolist then
+ local numberdata = list.numberdata
+ if numberdata then
+ collected[#collected+1] = numberdata
+ end
+ end
+ end
+ sections.load = functions.dummy
+end
+
+table.setmetatableindex(collected, function(t,i)
+ sections.load()
+ return collected[i] or { }
+end)
+
+--
+
+sections.levelmap = sections.levelmap or { }
+
+local levelmap = sections.levelmap
+
+storage.register("structures/sections/levelmap", sections.levelmap, "structures.sections.levelmap")
+
+sections.verbose = true
+
+levelmap.block = -1
+
+function sections.setlevel(name,level) -- level can be number or parent (=string)
+ local l = tonumber(level)
+ if not l then
+ l = levelmap[level]
+ end
+ if l and l > 0 then
+ levelmap[name] = l
+ else
+ -- error
+ end
+end
+
+function sections.getlevel(name)
+ return levelmap[name] or 0
+end
+
+function sections.setblock(name)
+ local block = name or data.block or "unknown" -- can be used to set the default
+ data.block = block
+ return block
+end
+
+function sections.pushblock(name)
+ counters.check(0) -- we assume sane usage of \page between blocks
+ local block = name or data.block
+ data.blocks[#data.blocks+1] = block
+ data.block = block
+ documents.reset()
+ return block
+end
+
+function sections.popblock()
+ data.blocks[#data.blocks] = nil
+ local block = data.blocks[#data.blocks] or data.block
+ data.block = block
+ documents.reset()
+ return block
+end
+
+function sections.currentblock()
+ return data.block or data.blocks[#data.blocks] or "unknown"
+end
+
+function sections.currentlevel()
+ return data.depth
+end
+
+function sections.getcurrentlevel()
+ context(data.depth)
+end
+
+local saveset = { } -- experiment, see sections/tricky-001.tex
+
+function sections.somelevel(given)
+ -- old number
+ local numbers = data.numbers
+
+ local ownnumbers = data.ownnumbers
+ local forced = data.forced
+ local status = data.status
+ local olddepth = data.depth
+ local givenname = given.metadata.name
+ local mappedlevel = levelmap[givenname]
+ local newdepth = tonumber(mappedlevel or (olddepth > 0 and olddepth) or 1) -- hm, levelmap only works for section-*
+ local directives = given.directives
+ local resetset = directives and directives.resetset or ""
+ -- local resetter = sets.getall("structure:resets",data.block,resetset)
+ -- a trick to permit userdata to overload title, ownnumber and reference
+ -- normally these are passed as argument but nowadays we provide several
+ -- interfaces (we need this because we want to be compatible)
+ if trace_detail then
+ report_structure("name %a, mapped level %a, old depth %a, new depth %a, reset set %a",
+ givenname,mappedlevel,olddepth,newdepth,resetset)
+ end
+ local u = given.userdata
+ if u then
+ -- kind of obsolete as we can pass them directly anyway
+ if u.reference and u.reference ~= "" then given.metadata.reference = u.reference ; u.reference = nil end
+ if u.ownnumber and u.ownnumber ~= "" then given.numberdata.ownnumber = u.ownnumber ; u.ownnumber = nil end
+ if u.title and u.title ~= "" then given.titledata.title = u.title ; u.title = nil end
+ if u.bookmark and u.bookmark ~= "" then given.titledata.bookmark = u.bookmark ; u.bookmark = nil end
+ if u.label and u.label ~= "" then given.titledata.label = u.label ; u.label = nil end
+ end
+ -- so far for the trick
+ if saveset then
+ saveset[newdepth] = (resetset ~= "" and resetset) or saveset[newdepth] or ""
+ end
+ if newdepth > olddepth then
+ for i=olddepth+1,newdepth do
+ local s = tonumber(sets.get("structure:resets",data.block,saveset and saveset[i] or resetset,i))
+ if trace_detail then
+ report_structure("new depth %s, old depth %s, reset set %a, reset value %a, current %a",olddepth,newdepth,resetset,s,numbers[i])
+ end
+ if not s or s == 0 then
+ numbers[i] = numbers[i] or 0
+ ownnumbers[i] = ownnumbers[i] or ""
+ else
+ numbers[i] = s - 1
+ ownnumbers[i] = ""
+ end
+ status[i] = { }
+ end
+ elseif newdepth < olddepth then
+ for i=olddepth,newdepth+1,-1 do
+ local s = tonumber(sets.get("structure:resets",data.block,saveset and saveset[i] or resetset,i))
+ if trace_detail then
+ report_structure("new depth %s, old depth %s, reset set %a, reset value %a, current %a",olddepth,newdepth,resetset,s,numbers[i])
+ end
+ if not s or s == 0 then
+ numbers[i] = numbers[i] or 0
+ ownnumbers[i] = ownnumbers[i] or ""
+ else
+ numbers[i] = s - 1
+ ownnumbers[i] = ""
+ end
+ status[i] = nil
+ end
+ end
+ counters.check(newdepth)
+ ownnumbers[newdepth] = given.numberdata.ownnumber or ""
+ given.numberdata.ownnumber = nil
+ data.depth = newdepth
+ -- new number
+ olddepth = newdepth
+ if given.metadata.increment then
+ local oldn, newn = numbers[newdepth] or 0, 0
+ local fd = forced[newdepth]
+ if fd then
+ if fd[1] == "add" then
+ newn = oldn + fd[2] + 1
+ else
+ newn = fd[2] + 1
+ end
+ if newn < 0 then
+ newn = 1 -- maybe zero is nicer
+ end
+ forced[newdepth] = nil
+ if trace_detail then
+ report_structure("old depth %a, new depth %a, old n %a, new n %a, forced %t",olddepth,newdepth,oldn,newn,fd)
+ end
+ else
+ newn = oldn + 1
+ if trace_detail then
+ report_structure("old depth %a, new depth %a, old n %a, new n %a, increment",olddepth,newdepth,oldn,newn)
+ end
+ end
+ numbers[newdepth] = newn
+ end
+ status[newdepth] = given or { }
+ for k, v in next, data.checkers do
+ if v[1] == newdepth and v[2] then
+ v[2](k)
+ end
+ end
+ local numberdata= given.numberdata
+ if not numberdata then
+ -- probably simplified to nothing
+ numberdata = { }
+ given.numberdata = numberdata
+ end
+
+ local n = { }
+ for i=1,newdepth do
+ n[i] = numbers[i]
+ end
+ numberdata.numbers = n
+-- numberdata.numbers = fastcopy(numbers)
+
+ if #ownnumbers > 0 then
+ numberdata.ownnumbers = fastcopy(ownnumbers)
+ end
+ if trace_detail then
+ report_structure("name %a, numbers % a, own numbers % a",givenname,numberdata.numbers,numberdata.ownnumbers)
+ end
+
+ local metadata = given.metadata
+ local references = given.references
+
+ local tag = references.tag or tags.getid(metadata.kind,metadata.name)
+ if tag and tag ~= "" and tag ~= "?" then
+ references.tag = tag
+ end
+
+ local setcomponent = structures.references.setcomponent
+ if setcomponent then
+ setcomponent(given) -- might move to the tex end
+ end
+
+ references.section = sections.save(given)
+ -- given.numberdata = nil
+end
+
+function sections.reportstructure()
+ if sections.verbose then
+ local numbers, ownnumbers, status, depth = data.numbers, data.ownnumbers, data.status, data.depth
+ local d = status[depth]
+ local o = concat(ownnumbers,".",1,depth)
+ local n = (numbers and concat(numbers,".",1,min(depth,#numbers))) or 0
+ local l = d.titledata.title or ""
+ local t = (l ~= "" and l) or d.titledata.title or "[no title]"
+ local m = d.metadata.name
+ if o and not find(o,"^%.*$") then
+ report_structure("%s @ level %i : (%s) %s -> %s",m,depth,n,o,t)
+ elseif d.directives and d.directives.hidenumber then
+ report_structure("%s @ level %i : (%s) -> %s",m,depth,n,t)
+ else
+ report_structure("%s @ level %i : %s -> %s",m,depth,n,t)
+ end
+ end
+end
+
+function sections.setnumber(depth,n)
+ local forced, depth, new = data.forced, depth or data.depth, tonumber(n)
+ if type(n) == "string" then
+ if find(n,"^[%+%-]") then
+ forced[depth] = { "add", new }
+ else
+ forced[depth] = { "set", new }
+ end
+ else
+ forced[depth] = { "set", new }
+ end
+end
+
+function sections.numberatdepth(depth)
+ return data.numbers[tonumber(depth) or sections.getlevel(depth) or 0] or 0
+end
+
+function sections.numbers()
+ return data.numbers
+end
+
+function sections.matchingtilldepth(depth,numbers,parentnumbers)
+ local dn = parentnumbers or data.numbers
+ local ok = false
+ for i=1,depth do
+ if dn[i] == numbers[i] then
+ ok = true
+ else
+ return false
+ end
+ end
+ return ok
+end
+
+function sections.getnumber(depth) -- redefined later ...
+ context(data.numbers[depth] or 0)
+end
+
+function sections.set(key,value)
+ data.status[data.depth][key] = value -- may be nil for a reset
+end
+
+function sections.cct()
+ local metadata = data.status[data.depth].metadata
+ context(metadata and metadata.catcodes or ctxcatcodes)
+end
+
+-- this one will become: return catcode, d (etc)
+
+function sections.structuredata(depth,key,default,honorcatcodetable) -- todo: spec table and then also depth
+ if depth then
+ depth = levelmap[depth] or tonumber(depth)
+ end
+ if not depth or depth == 0 then
+ depth = data.depth
+ end
+ local data = data.status[depth]
+ local d
+ if data then
+ if find(key,"%.") then
+ d = accesstable(key,data)
+ else
+ d = data.titledata
+ d = d and d[key]
+ end
+ end
+ if d and type(d) ~= "table" then
+ if honorcatcodetable == true or honorcatcodetable == v_auto then
+ local metadata = data.metadata
+ local catcodes = metadata and metadata.catcodes
+ if catcodes then
+ context.sprint(catcodes,d)
+ else
+ context(d)
+ end
+ elseif not honorcatcodetable or honorcatcodetable == "" then
+ context(d)
+ else
+ local catcodes = catcodenumbers[honorcatcodetable]
+ if catcodes then
+ context.sprint(catcodes,d)
+ else
+ context(d)
+ end
+ end
+ elseif default then
+ context(default)
+ end
+end
+
+function sections.userdata(depth,key,default)
+ if depth then
+ depth = levelmap[depth] or tonumber(depth)
+ end
+ if not depth or depth == 0 then
+ depth = data.depth
+ end
+ if depth > 0 then
+ local userdata = data.status[depth]
+ userdata = userdata and userdata.userdata
+ userdata = (userdata and userdata[key]) or default
+ if userdata then
+ context(userdata)
+ end
+ end
+end
+
+function sections.setchecker(name,level,command) -- hm, checkers are not saved
+ data.checkers[name] = (name and command and level >= 0 and { level, command }) or nil
+end
+
+function sections.current()
+ return data.status[data.depth]
+end
+
+function sections.depthnumber(n)
+ local depth = data.depth
+ if not n or n == 0 then
+ n = depth
+ elseif n < 0 then
+ n = depth + n
+ end
+ return context(data.numbers[n] or 0)
+end
+
+function sections.autodepth(numbers)
+ for i=#numbers,1,-1 do
+ if numbers[i] ~= 0 then
+ return i
+ end
+ end
+ return 0
+end
+
+--
+
+function structures.currentsectionnumber() -- brr, namespace wrong
+ local sc = sections.current()
+ return sc and sc.numberdata
+end
+
+-- \dorecurse{3} {
+-- \chapter{Blabla} \subsection{bla 1 1} \subsection{bla 1 2}
+-- \section{bla 2} \subsection{bla 2 1} \subsection{bla 2 2}
+-- }
+
+-- sign=all => also zero and negative
+-- sign=positive => also zero
+-- sign=hang => llap sign
+
+--~ todo: test this
+--~
+
+local function process(index,numbers,ownnumbers,criterium,separatorset,conversion,conversionset,index,entry,result,preceding,done)
+ -- todo: too much (100 steps)
+ local number = numbers and (numbers[index] or 0)
+ local ownnumber = ownnumbers and ownnumbers[index] or ""
+ if number > criterium or (ownnumber ~= "") then
+ local block = (entry.block ~= "" and entry.block) or sections.currentblock() -- added
+ if preceding then
+ local separator = sets.get("structure:separators",block,separatorset,preceding,".")
+ if separator then
+ if result then
+ result[#result+1] = strippedprocessor(separator)
+ else
+ applyprocessor(separator)
+ end
+ end
+ preceding = false
+ end
+ if result then
+ if ownnumber ~= "" then
+ result[#result+1] = ownnumber
+ elseif conversion and conversion ~= "" then -- traditional (e.g. used in itemgroups) .. inherited!
+ result[#result+1] = converters.convert(conversion,number)
+ else
+ local theconversion = sets.get("structure:conversions",block,conversionset,index,"numbers")
+ result[#result+1] = converters.convert(theconversion,number)
+ end
+ else
+ if ownnumber ~= "" then
+ applyprocessor(ownnumber)
+ elseif conversion and conversion ~= "" then -- traditional (e.g. used in itemgroups)
+ context.convertnumber(conversion,number)
+ else
+ local theconversion = sets.get("structure:conversions",block,conversionset,index,"numbers")
+ local data = startapplyprocessor(theconversion)
+ context.convertnumber(data or "numbers",number)
+ stopapplyprocessor()
+ end
+ end
+ return index, true
+ else
+ return preceding or false, done
+ end
+end
+
+function sections.typesetnumber(entry,kind,...) -- kind='section','number','prefix'
+ if entry and entry.hidenumber ~= true then -- can be nil
+ local separatorset = ""
+ local conversionset = ""
+ local conversion = ""
+ local groupsuffix = ""
+ local stopper = ""
+ local starter = ""
+ local connector = ""
+ local set = ""
+ local segments = ""
+ local criterium = ""
+ for d=1,select("#",...) do
+ local data = select(d,...) -- can be multiple parametersets
+ if data then
+ if separatorset == "" then separatorset = data.separatorset or "" end
+ if conversionset == "" then conversionset = data.conversionset or "" end
+ if conversion == "" then conversion = data.conversion or "" end
+ if groupsuffix == "" then groupsuffix = data.groupsuffix or "" end
+ if stopper == "" then stopper = data.stopper or "" end
+ if starter == "" then starter = data.starter or "" end
+ if connector == "" then connector = data.connector or "" end
+ if set == "" then set = data.set or "" end
+ if segments == "" then segments = data.segments or "" end
+ if criterium == "" then criterium = data.criterium or "" end
+ end
+ end
+ if separatorset == "" then separatorset = "default" end
+ if conversionset == "" then conversionset = "default" end -- not used
+ if conversion == "" then conversion = nil end
+ if groupsuffix == "" then groupsuffix = nil end
+ if stopper == "" then stopper = nil end
+ if starter == "" then starter = nil end
+ if connector == "" then connector = nil end
+ if set == "" then set = "default" end
+ if segments == "" then segments = nil end
+ --
+ if criterium == v_strict then
+ criterium = 0
+ elseif criterium == v_positive then
+ criterium = -1
+ elseif criterium == v_all then
+ criterium = -1000000
+ else
+ criterium = 0
+ end
+ --
+ local firstprefix, lastprefix = 0, 16
+ if segments then
+ local f, l = match(tostring(segments),"^(.-):(.+)$")
+ if l == "*" then
+ l = 100 -- new
+ end
+ if f and l then
+ -- 0:100, chapter:subsubsection
+ firstprefix = tonumber(f) or sections.getlevel(f) or 0
+ lastprefix = tonumber(l) or sections.getlevel(l) or 100
+ else
+ -- 3, section
+ local fl = tonumber(segments) or sections.getlevel(segments) -- generalize
+ if fl then
+ firstprefix = fl
+ lastprefix = fl
+ end
+ end
+ end
+ --
+ local numbers, ownnumbers = entry.numbers, entry.ownnumbers
+ if numbers then
+ local done, preceding = false, false
+ --
+ local result = kind == "direct" and { }
+ if result then
+ connector = false
+ end
+ --
+ local prefixlist = set and sets.getall("structure:prefixes","",set) -- "" == block
+ if starter then
+ if result then
+ result[#result+1] = strippedprocessor(starter)
+ else
+ applyprocessor(starter)
+ end
+ end
+ if prefixlist and (kind == 'section' or kind == 'prefix' or kind == 'direct') then
+ -- find valid set (problem: for sectionnumber we should pass the level)
+ -- no holes
+ local b, e, bb, ee = 1, #prefixlist, 0, 0
+ -- find last valid number
+ for k=e,b,-1 do
+ local prefix = prefixlist[k]
+ local index = sections.getlevel(prefix) or k
+ if index >= firstprefix and index <= lastprefix then
+ local number = numbers and numbers[index]
+ if number then
+ local ownnumber = ownnumbers and ownnumbers[index] or ""
+ if number > 0 or (ownnumber ~= "") then
+ break
+ else
+ e = k -1
+ end
+ end
+ end
+ end
+ -- find valid range
+ for k=b,e do
+ local prefix = prefixlist[k]
+ local index = sections.getlevel(prefix) or k
+ if index >= firstprefix and index <= lastprefix then
+ local number = numbers and numbers[index]
+ if number then
+ local ownnumber = ownnumbers and ownnumbers[index] or ""
+ if number > 0 or (ownnumber ~= "") then
+ if bb == 0 then bb = k end
+ ee = k
+ else
+ bb, ee = 0, 0
+ end
+ else
+ break
+ end
+ end
+ end
+ -- print valid range
+ for k=bb,ee do
+ local prefix = prefixlist[k]
+ local index = sections.getlevel(prefix) or k
+ if index >= firstprefix and index <= lastprefix then
+ -- process(index,result)
+ preceding, done = process(index,numbers,ownnumbers,criterium,separatorset,conversion,conversionset,index,entry,result,preceding,done)
+ end
+ end
+ else
+ -- also holes check
+ for index=firstprefix,lastprefix do
+ -- process(index,result)
+ preceding, done = process(index,numbers,ownnumbers,criterium,separatorset,conversion,conversionset,index,entry,result,preceding,done)
+ end
+ end
+ --
+ if done then
+ if connector and kind == 'prefix' then
+ if result then
+ -- can't happen as we're in 'direct'
+ else
+ applyprocessor(connector)
+ end
+ else
+if groupsuffix and kind ~= "prefix" then
+ if result then
+ result[#result+1] = strippedprocessor(groupsuffix)
+ else
+ applyprocessor(groupsuffix)
+ end
+end
+ if stopper then
+ if result then
+ result[#result+1] = strippedprocessor(stopper)
+ else
+ applyprocessor(stopper)
+ end
+ end
+ end
+ end
+ return result -- a table !
+ else
+ -- report_structure("error: no numbers")
+ end
+ end
+end
+
+function sections.title()
+ local sc = sections.current()
+ if sc then
+ helpers.title(sc.titledata.title,sc.metadata)
+ end
+end
+
+function sections.findnumber(depth,what) -- needs checking (looks wrong and slow too)
+ local data = data.status[depth or data.depth]
+ if data then
+ local index = data.references.section
+ local collected = sections.collected
+ local sectiondata = collected[index]
+ if sectiondata and sectiondata.hidenumber ~= true then -- can be nil
+ local quit = what == v_previous or what == v_next
+ if what == v_first or what == v_previous then
+ for i=index,1,-1 do
+ local s = collected[i]
+ if s then
+ local n = s.numbers
+ if #n == depth and n[depth] and n[depth] ~= 0 then
+ sectiondata = s
+ if quit then
+ break
+ end
+ elseif #n < depth then
+ break
+ end
+ end
+ end
+ elseif what == v_last or what == v_next then
+ for i=index,#collected do
+ local s = collected[i]
+ if s then
+ local n = s.numbers
+ if #n == depth and n[depth] and n[depth] ~= 0 then
+ sectiondata = s
+ if quit then
+ break
+ end
+ elseif #n < depth then
+ break
+ end
+ end
+ end
+ end
+ return sectiondata
+ end
+ end
+end
+
+function sections.finddata(depth,what)
+ local data = data.status[depth or data.depth]
+ if data then
+ -- if sectiondata and sectiondata.hidenumber ~= true then -- can be nil
+ local index = data.references.listindex
+ if index then
+ local collected = structures.lists.collected
+ local quit = what == v_previous or what == v_next
+ if what == v_first or what == v_previous then
+ for i=index-1,1,-1 do
+ local s = collected[i]
+ if not s then
+ break
+ elseif s.metadata.kind == "section" then -- maybe check on name
+ local n = s.numberdata.numbers
+ if #n == depth and n[depth] and n[depth] ~= 0 then
+ data = s
+ if quit then
+ break
+ end
+ elseif #n < depth then
+ break
+ end
+ end
+ end
+ elseif what == v_last or what == v_next then
+ for i=index+1,#collected do
+ local s = collected[i]
+ if not s then
+ break
+ elseif s.metadata.kind == "section" then -- maybe check on name
+ local n = s.numberdata.numbers
+ if #n == depth and n[depth] and n[depth] ~= 0 then
+ data = s
+ if quit then
+ break
+ end
+ elseif #n < depth then
+ break
+ end
+ end
+ end
+ end
+ end
+ return data
+ end
+end
+
+function sections.internalreference(sectionname,what) -- to be used in pagebuilder (no marks used)
+ local r = type(sectionname) == "number" and sectionname or registered[sectionname]
+ if r then
+ local data = sections.finddata(r.level,what)
+ return data and data.references and data.references.internal
+ end
+end
+
+function sections.fullnumber(depth,what)
+ local sectiondata = sections.findnumber(depth,what)
+ if sectiondata then
+ sections.typesetnumber(sectiondata,'section',sectiondata)
+ end
+end
+
+function sections.getnumber(depth,what) -- redefined here
+ local sectiondata = sections.findnumber(depth,what)
+ context((sectiondata and sectiondata.numbers[depth]) or 0)
+end
+
+-- experimental
+
+local levels = { }
+
+--~ function commands.autonextstructurelevel(level)
+--~ if level > #levels then
+--~ for i=#levels+1,level do
+--~ levels[i] = ""
+--~ end
+--~ end
+--~ local finish = concat(levels,"\n",level) or ""
+--~ for i=level+1,#levels do
+--~ levels[i] = ""
+--~ end
+--~ levels[level] = [[\finalizeautostructurelevel]]
+--~ context(finish)
+--~ end
+
+--~ function commands.autofinishstructurelevels()
+--~ local finish = concat(levels,"\n") or ""
+--~ levels = { }
+--~ context(finish)
+--~ end
+
+function commands.autonextstructurelevel(level)
+ if level > #levels then
+ for i=#levels+1,level do
+ levels[i] = false
+ end
+ else
+ for i=level,#levels do
+ if levels[i] then
+ context.finalizeautostructurelevel()
+ levels[i] = false
+ end
+ end
+ end
+ levels[level] = true
+end
+
+function commands.autofinishstructurelevels()
+ for i=1,#levels do
+ if levels[i] then
+ context.finalizeautostructurelevel()
+ end
+ end
+ levels = { }
+end
+
+-- interface (some are actually already commands, like sections.fullnumber)
+
+commands.structurenumber = function() sections.fullnumber() end
+commands.structuretitle = function() sections.title () end
+
+commands.structurevariable = function(name) sections.structuredata(nil,name) end
+commands.structureuservariable = function(name) sections.userdata (nil,name) end
+commands.structurecatcodedget = function(name) sections.structuredata(nil,name,nil,true) end
+commands.structuregivencatcodedget = function(name,catcode) sections.structuredata(nil,name,nil,catcode) end
+commands.structureautocatcodedget = function(name,catcode) sections.structuredata(nil,name,nil,catcode) end
+
+commands.namedstructurevariable = function(depth,name) sections.structuredata(depth,name) end
+commands.namedstructureuservariable = function(depth,name) sections.userdata (depth,name) end
+
+--
+
+function commands.setsectionblock (name) context(sections.setblock(name)) end
+function commands.pushsectionblock(name) context(sections.pushblock(name)) end
+function commands.popsectionblock () context(sections.popblock()) end
+
+--
+
+local byway = "^" .. v_by -- ugly but downward compatible
+
+function commands.way(way)
+ context((gsub(way,byway,"")))
+end