summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/context/base/strc-lst.lua
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex/context/base/strc-lst.lua')
-rw-r--r--Master/texmf-dist/tex/context/base/strc-lst.lua296
1 files changed, 213 insertions, 83 deletions
diff --git a/Master/texmf-dist/tex/context/base/strc-lst.lua b/Master/texmf-dist/tex/context/base/strc-lst.lua
index fefbe52ce29..21015e43a21 100644
--- a/Master/texmf-dist/tex/context/base/strc-lst.lua
+++ b/Master/texmf-dist/tex/context/base/strc-lst.lua
@@ -16,37 +16,67 @@ local tonumber = tonumber
local texsprint, texprint, texwrite, texcount = tex.sprint, tex.print, tex.write, tex.count
local concat, insert, remove = table.concat, table.insert, table.remove
local lpegmatch = lpeg.match
+local simple_hash_to_string, settings_to_hash = utilities.parsers.simple_hash_to_string, utilities.parsers.settings_to_hash
+local allocate, checked = utilities.storage.allocate, utilities.storage.checked
-local trace_lists = false trackers.register("structure.lists", function(v) trace_lists = v end)
+local trace_lists = false trackers.register("structures.lists", function(v) trace_lists = v end)
-local ctxcatcodes = tex.ctxcatcodes
+local report_lists = logs.reporter("structure","lists")
-structure.lists = structure.lists or { }
-structure.sections = structure.sections or { }
-structure.helpers = structure.helpers or { }
-structure.documents = structure.documents or { }
-structure.pages = structure.pages or { }
+local ctxcatcodes = tex.ctxcatcodes
-local lists = structure.lists
-local sections = structure.sections
-local helpers = structure.helpers
-local documents = structure.documents
-local pages = structure.pages
+local structures = structures
+local lists = structures.lists
+local sections = structures.sections
+local helpers = structures.helpers
+local documents = structures.documents
+local pages = structures.pages
+local tags = structures.tags
+local references = structures.references
-lists.collected = lists.collected or { }
-lists.tobesaved = lists.tobesaved or { }
-lists.enhancers = lists.enhancers or { }
-lists.internals = lists.internals or { }
-lists.ordered = lists.ordered or { }
+local collected = allocate()
+local tobesaved = allocate()
+local cached = allocate()
+local pushed = allocate()
+
+lists.collected = collected
+lists.tobesaved = tobesaved
+
+lists.enhancers = lists.enhancers or { }
+lists.internals = allocate(lists.internals or { }) -- to be checked
+lists.ordered = allocate(lists.ordered or { }) -- to be checked
+lists.cached = cached
+lists.pushed = pushed
+
+references.specials = references.specials or { }
local variables = interfaces.variables
-local matching_till_depth, number_at_depth = sections.matching_till_depth, sections.number_at_depth
+local matchingtilldepth, numberatdepth = sections.matchingtilldepth, sections.numberatdepth
+
+-- -- -- -- -- --
+
+local function zerostrippedconcat(t,separator) -- for the moment not public
+ local f, l = 1, #t
+ for i=f,l do
+ if t[i] == 0 then
+ f = f + 1
+ end
+ end
+ for i=l,f,-1 do
+ if t[i] == 0 then
+ l = l - 1
+ end
+ end
+ return concat(t,separator,f,l)
+end
+
+-- -- -- -- -- --
local function initializer()
-- create a cross reference between internal references
-- and list entries
local collected = lists.collected
- local internals = jobreferences.internals
+ local internals = checked(references.internals)
local ordered = lists.ordered
for i=1,#collected do
local c = collected[i]
@@ -77,13 +107,10 @@ local function initializer()
end
end
-if job then
- job.register('structure.lists.collected', structure.lists.tobesaved, initializer)
-end
-
-local cached, pushed = { }, { }
+job.register('structures.lists.collected', tobesaved, initializer)
function lists.push(t)
+ local m = t.metadata
local r = t.references
local i = (r and r.internal) or 0 -- brrr
local p = pushed[i]
@@ -105,21 +132,49 @@ function lists.enhance(n)
-- todo: symbolic names for counters
local l = cached[n]
if l then
+ local metadata = l.metadata
+ local references = l.references
--
l.directives = nil -- might change
-- save in the right order (happens at shipout)
lists.tobesaved[#lists.tobesaved+1] = l
-- default enhancer (cross referencing)
- l.references.realpage = texcount.realpageno
+ references.realpage = texcount.realpageno
+ -- tags
+ local kind = metadata.kind
+ local name = metadata.name
+ if references then
+ references.tag = tags.getid(kind,name)
+ end
-- specific enhancer (kind of obsolete)
- local kind = l.metadata.kind
local enhancer = kind and lists.enhancers[kind]
if enhancer then
enhancer(l)
end
+ return l
end
end
+--~ function lists.enforce(n)
+--~ -- todo: symbolic names for counters
+--~ local l = cached[n]
+--~ if l then
+--~ --
+--~ l.directives = nil -- might change
+--~ -- save in the right order (happens at shipout)
+--~ lists.tobesaved[#lists.tobesaved+1] = l
+--~ -- default enhancer (cross referencing)
+--~ l.references.realpage = texcount.realpageno
+--~ -- specific enhancer (kind of obsolete)
+--~ local kind = l.metadata.kind
+--~ local enhancer = kind and lists.enhancers[kind]
+--~ if enhancer then
+--~ enhancer(l)
+--~ end
+--~ return l
+--~ end
+--~ end
+
-- we can use level instead but we can also decide to remove level from the metadata
local nesting = { }
@@ -139,17 +194,55 @@ end
-- will be split
-local function filter_collected(names, criterium, number, collected, nested)
+-- Historically we had blocks but in the mkiv approach that could as well be a level
+-- which would simplify things a bit.
+
+local splitter = lpeg.splitat(":")
+
+-- this will become filtercollected(specification) and then we'll also have sectionblock as key
+
+local sorters = {
+ [variables.command] = function(a,b)
+ if a.metadata.kind == "command" or b.metadata.kind == "command" then
+ return a.references.internal < b.references.internal
+ else
+ return a.references.order < b.references.order
+ end
+ end,
+ [variables.all] = function(a,b)
+ return a.references.internal < b.references.internal
+ end,
+}
+
+-- some day soon we will pass a table
+
+local function filtercollected(names, criterium, number, collected, forced, nested, sortorder) -- names is hash or string
local numbers, depth = documents.data.numbers, documents.data.depth
- local hash, result, all, detail = { }, { }, not names or names == "" or names == variables.all, nil
- names, criterium = gsub(names," ",""), gsub(criterium," ","")
- if trace_lists then
- logs.report("lists","filtering names: %s, criterium: %s, number: %s",names,criterium,number or "-")
+ local result, nofresult, detail = { }, 0, nil
+ local block = false -- all
+ criterium = gsub(criterium or ""," ","") -- not needed
+ -- new, will be applied stepwise
+ local wantedblock, wantedcriterium = lpegmatch(splitter,criterium) -- block:criterium
+ if not wantedcriterium then
+ block = documents.data.block
+ elseif wantedblock == "" or wantedblock == variables.all or wantedblock == variables.text then
+ criterium = wantedcriterium ~= "" and wantedcriterium or criterium
+ else
+ block, criterium = wantedblock, wantedcriterium
end
- if not all then
- for s in gmatch(names,"[^, ]+") do -- sort of settings to hash
- hash[s] = true
- end
+ if block == "" then
+ block = false
+ end
+--~ print(">>",block,criterium)
+ --
+ forced = forced or { } -- todo: also on other branched, for the moment only needed for bookmarks
+ if type(names) == "string" then
+ names = settings_to_hash(names)
+ end
+ local all = not next(names) or names[variables.all] or false
+ if trace_lists then
+ report_lists("filtering names: %s, criterium: %s, block: %s, number: %s",
+ simple_hash_to_string(names),criterium,block or "*", number or "-")
end
if criterium == variables.intro then
-- special case, no structure yet
@@ -157,37 +250,40 @@ local function filter_collected(names, criterium, number, collected, nested)
local v = collected[i]
local r = v.references
if r and r.section == 0 then
- result[#result+1] = v
+ nofresult = nofresult + 1
+ result[nofresult] = v
end
end
- elseif criterium == variables.all or criterium == variables.text then
+ elseif all or criterium == variables.all or criterium == variables.text then
for i=1,#collected do
local v = collected[i]
local r = v.references
if r then
- local sectionnumber = (r.section == 0) or jobsections.collected[r.section]
- if sectionnumber then -- and not sectionnumber.hidenumber then
- local metadata = v.metadata
- if metadata and not metadata.nolist and (all or hash[metadata.name or false]) then
- result[#result+1] = v
+ local metadata = v.metadata
+ if metadata then
+ local name = metadata.name or false
+ local sectionnumber = (r.section == 0) or sections.collected[r.section]
+ if forced[name] or (sectionnumber and not metadata.nolist and (all or names[name])) then -- and not sectionnumber.hidenumber then
+ nofresult = nofresult + 1
+ result[nofresult] = v
end
end
end
end
elseif criterium == variables.current then
if depth == 0 then
- return filter_collected(names,variables.intro,number,collected)
+ return filtercollected(names,variables.intro,number,collected,forced,false,sortorder)
else
for i=1,#collected do
local v = collected[i]
local r = v.references
- if r then
- local sectionnumber = jobsections.collected[r.section]
+ if r and (not block or not r.block or block == r.block) then
+ local sectionnumber = sections.collected[r.section]
if sectionnumber then -- and not sectionnumber.hidenumber then
local cnumbers = sectionnumber.numbers
local metadata = v.metadata
if cnumbers then
- if metadata and not metadata.nolist and (all or hash[metadata.name or false]) and #cnumbers > depth then
+ if metadata and not metadata.nolist and (all or names[metadata.name or false]) and #cnumbers > depth then
local ok = true
for d=1,depth do
local cnd = cnumbers[d]
@@ -197,7 +293,8 @@ local function filter_collected(names, criterium, number, collected, nested)
end
end
if ok then
- result[#result+1] = v
+ nofresult = nofresult + 1
+ result[nofresult] = v
end
end
end
@@ -208,19 +305,19 @@ local function filter_collected(names, criterium, number, collected, nested)
elseif criterium == variables.here then
-- this is quite dirty ... as cnumbers is not sparse we can misuse #cnumbers
if depth == 0 then
- return filter_collected(names,variables.intro,number,collected)
+ return filtercollected(names,variables.intro,number,collected,forced,false,sortorder)
else
for i=1,#collected do
local v = collected[i]
local r = v.references
- if r then
- local sectionnumber = jobsections.collected[r.section]
+ if r then -- and (not block or not r.block or block == r.block) then
+ local sectionnumber = sections.collected[r.section]
if sectionnumber then -- and not sectionnumber.hidenumber then
local cnumbers = sectionnumber.numbers
local metadata = v.metadata
if cnumbers then
---~ print(#cnumbers, depth, table.concat(cnumbers))
- if metadata and not metadata.nolist and (all or hash[metadata.name or false]) and #cnumbers >= depth then
+--~ print(#cnumbers, depth, concat(cnumbers))
+ if metadata and not metadata.nolist and (all or names[metadata.name or false]) and #cnumbers >= depth then
local ok = true
for d=1,depth do
local cnd = cnumbers[d]
@@ -230,7 +327,8 @@ local function filter_collected(names, criterium, number, collected, nested)
end
end
if ok then
- result[#result+1] = v
+ nofresult = nofresult + 1
+ result[nofresult] = v
end
end
end
@@ -240,18 +338,18 @@ local function filter_collected(names, criterium, number, collected, nested)
end
elseif criterium == variables.previous then
if depth == 0 then
- return filter_collected(names,variables.intro,number,collected)
+ return filtercollected(names,variables.intro,number,collected,forced,false,sortorder)
else
for i=1,#collected do
local v = collected[i]
local r = v.references
- if r then
- local sectionnumber = jobsections.collected[r.section]
+ if r and (not block or not r.block or block == r.block) then
+ local sectionnumber = sections.collected[r.section]
if sectionnumber then -- and not sectionnumber.hidenumber then
local cnumbers = sectionnumber.numbers
local metadata = v.metadata
if cnumbers then
- if metadata and not metadata.nolist and (all or hash[metadata.name or false]) and #cnumbers >= depth then
+ if metadata and not metadata.nolist and (all or names[metadata.name or false]) and #cnumbers >= depth then
local ok = true
for d=1,depth-1 do
local cnd = cnumbers[d]
@@ -261,7 +359,8 @@ local function filter_collected(names, criterium, number, collected, nested)
end
end
if ok then
- result[#result+1] = v
+ nofresult = nofresult + 1
+ result[nofresult] = v
end
end
end
@@ -272,16 +371,16 @@ local function filter_collected(names, criterium, number, collected, nested)
elseif criterium == variables["local"] then -- not yet ok
local nested = nesting[#nesting]
if nested then
- return filter_collected(names,nested.name,nested.number,collected,nested)
+ return filtercollected(names,nested.name,nested.number,collected,forced,nested,sortorder)
elseif sections.autodepth(documents.data.numbers) == 0 then
- return filter_collected(names,variables.all,number,collected)
+ return filtercollected(names,variables.all,number,collected,forced,false,sortorder)
else
- return filter_collected(names,variables.current,number,collected)
+ return filtercollected(names,variables.current,number,collected,forced,false,sortorder)
end
else -- sectionname, number
-- not the same as register
local depth = sections.getlevel(criterium)
- local number = tonumber(number) or number_at_depth(depth) or 0
+ local number = tonumber(number) or numberatdepth(depth) or 0
if trace_lists then
local t = sections.numbers()
detail = format("depth: %s, number: %s, numbers: %s, startset: %s",depth,number,(#t>0 and concat(t,".",1,depth)) or "?",#collected)
@@ -291,14 +390,15 @@ local function filter_collected(names, criterium, number, collected, nested)
for i=1,#collected do
local v = collected[i]
local r = v.references
- if r then
- local sectionnumber = jobsections.collected[r.section]
+ if r then -- block ?
+ local sectionnumber = sections.collected[r.section]
if sectionnumber then
local metadata = v.metadata
local cnumbers = sectionnumber.numbers
if cnumbers then
- if (all or hash[metadata.name or false]) and #cnumbers >= depth and matching_till_depth(depth,cnumbers,parent) then
- result[#result+1] = v
+ if (all or names[metadata.name or false]) and #cnumbers >= depth and matchingtilldepth(depth,cnumbers,parent) then
+ nofresult = nofresult + 1
+ result[nofresult] = v
end
end
end
@@ -308,34 +408,58 @@ local function filter_collected(names, criterium, number, collected, nested)
end
if trace_lists then
if detail then
- logs.report("lists","criterium: %s, %s, found: %s",criterium,detail,#result)
+ report_lists("criterium: %s, block: %s, %s, found: %s",criterium,block or "*",detail,#result)
else
- logs.report("lists","criterium: %s, found: %s",criterium,#result)
+ report_lists("criterium: %s, block: %s, found: %s",criterium,block or "*",#result)
+ end
+ end
+
+ if sortorder then -- experiment
+ local sorter = sorters[sortorder]
+ if sorter then
+ if trace_lists then
+ report_lists("sorting list using method %s",sortorder)
+ end
+ for i=1,#result do
+ result[i].references.order = i
+ end
+ table.sort(result,sorter)
end
end
+
return result
end
-lists.filter_collected = filter_collected
-
-function lists.filter(names, criterium, number)
- return filter_collected(names, criterium, number, lists.collected)
+lists.filtercollected = filtercollected
+
+function lists.filter(specification)
+ return filtercollected(
+ specification.names,
+ specification.criterium,
+ specification.number,
+ lists.collected,
+ specification.forced,
+ false,
+ specification.order
+ )
end
lists.result = { }
-function lists.process(...)
- lists.result = lists.filter(...)
+function lists.process(specification)
+ lists.result = lists.filter(specification)
+ local specials = utilities.parsers.settings_to_hash(specification.extras or "")
+ specials = next(specials) and specials or nil
for i=1,#lists.result do
local r = lists.result[i]
local m = r.metadata
- texsprint(ctxcatcodes,format("\\processlistofstructure{%s}{%s}{%i}",m.name,m.kind,i))
---~ context.processlistofstructure(m.name,m.kind,i)
+ local s = specials and r.numberdata and specials[zerostrippedconcat(r.numberdata.numbers,".")] or ""
+ context.processlistofstructure(m.name,m.kind,i,s)
end
end
-function lists.analyze(...)
- lists.result = lists.filter(...)
+function lists.analyze(specification)
+ lists.result = lists.filter(specification)
end
function lists.userdata(name,r,tag) -- to tex (todo: xml)
@@ -365,9 +489,17 @@ function lists.location(n)
texsprint(l.references.internal or n)
end
+function lists.label(n,default)
+ local l = lists.result[n]
+ local t = l.titledata
+ if t then
+ texsprint(t.label or default or "")
+ end
+end
+
function lists.sectionnumber(name,n,spec)
local data = lists.result[n]
- local sectiondata = jobsections.collected[data.references.section]
+ local sectiondata = sections.collected[data.references.section]
-- hm, prefixnumber?
sections.typesetnumber(sectiondata,"prefix",spec,sectiondata) -- data happens to contain the spec too
end
@@ -390,7 +522,6 @@ function lists.savedtitle(name,n,tag)
local titledata = data.titledata
if titledata then
helpers.title(titledata[tag] or titledata.title or "",data.metadata)
---~ texsprint(ctxcatcodes,titledata[tag] or titledata.title or "")
end
end
end
@@ -411,7 +542,6 @@ function lists.savedprefixednumber(name,n)
helpers.prefix(data,data.prefixdata)
local numberdata = data.numberdata
if numberdata then
---~ print(name,n,table.serialize(numberdata))
sections.typesetnumber(numberdata,"number",numberdata or false)
end
end
@@ -469,7 +599,7 @@ end
local splitter = lpeg.splitat(":")
-function jobreferences.specials.order(var,actions) -- jobreferences.specials !
+function references.specials.order(var,actions) -- references.specials !
local operation = var.operation
if operation then
local kind, name, n = lpegmatch(splitter,operation)
@@ -480,7 +610,7 @@ function jobreferences.specials.order(var,actions) -- jobreferences.specials !
if r then
actions.realpage = r
var.operation = r -- brrr, but test anyway
- return jobreferences.specials.page(var,actions)
+ return references.specials.page(var,actions)
end
end
end