diff options
Diffstat (limited to 'Master/texmf-dist/tex/context/base/strc-lst.lua')
-rw-r--r-- | Master/texmf-dist/tex/context/base/strc-lst.lua | 296 |
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 |