diff options
Diffstat (limited to 'tex/context/base/strc-doc.lua')
-rw-r--r-- | tex/context/base/strc-doc.lua | 1912 |
1 files changed, 956 insertions, 956 deletions
diff --git a/tex/context/base/strc-doc.lua b/tex/context/base/strc-doc.lua index 37a16c414..50a9e67a0 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 |