diff options
Diffstat (limited to 'Master/texmf-dist/tex/context/base/strc-reg.lua')
-rw-r--r-- | Master/texmf-dist/tex/context/base/strc-reg.lua | 699 |
1 files changed, 411 insertions, 288 deletions
diff --git a/Master/texmf-dist/tex/context/base/strc-reg.lua b/Master/texmf-dist/tex/context/base/strc-reg.lua index c5b2c93741c..c19ae12d65c 100644 --- a/Master/texmf-dist/tex/context/base/strc-reg.lua +++ b/Master/texmf-dist/tex/context/base/strc-reg.lua @@ -7,39 +7,45 @@ if not modules then modules = { } end modules ['strc-reg'] = { } local next, type = next, type -local texwrite, texsprint, texcount = tex.write, tex.sprint, tex.count -local format, gmatch, concat = string.format, string.gmatch, table.concat +local texwrite, texcount = tex.write, tex.count +local format, gmatch = string.format, string.gmatch +local equal, concat, remove = table.are_equal, table.concat, table.remove local utfchar = utf.char local lpegmatch = lpeg.match +local allocate = utilities.storage.allocate -local trace_registers = false trackers.register("structure.registers", function(v) trace_registers = v end) +local trace_registers = false trackers.register("structures.registers", function(v) trace_registers = v end) -local ctxcatcodes = tex.ctxcatcodes +local report_registers = logs.reporter("structure","registers") -local variables = interfaces.variables +local structures = structures +local registers = structures.registers +local helpers = structures.helpers +local sections = structures.sections +local documents = structures.documents +local pages = structures.pages +local processors = structures.processors +local references = structures.references -local helpers = structure.helpers -local sections = structure.sections -local documents = structure.documents -local pages = structure.pages -local processors = structure.processors - -local mappings = sorters.mappings -local entries = sorters.entries -local replacements = sorters.replacements +local mappings = sorters.mappings +local entries = sorters.entries +local replacements = sorters.replacements local processor_split = processors.split -local matching_till_depth, number_at_depth = sections.matching_till_depth, sections.number_at_depth +local variables = interfaces.variables +local context = context + +local matchingtilldepth, numberatdepth = sections.matchingtilldepth, sections.numberatdepth -- some day we will share registers and lists (although there are some conceptual -- differences in the application of keywords) -local function filter_collected(names,criterium,number,collected,prevmode) +local function filtercollected(names,criterium,number,collected,prevmode) if not criterium or criterium == "" then criterium = variables.all end local data = documents.data local numbers, depth = data.numbers, data.depth - local hash, result, all, detail = { }, { }, not names or names == "" or names == variables.all, nil + local hash, result, nofresult, all, detail = { }, { }, 0, not names or names == "" or names == variables.all, nil if not all then for s in gmatch(names,"[^, ]+") do hash[s] = true @@ -49,18 +55,20 @@ local function filter_collected(names,criterium,number,collected,prevmode) for i=1,#collected do local v = collected[i] if all then - result[#result+1] = v + nofresult = nofresult + 1 + result[nofresult] = v else local vmn = v.metadata and v.metadata.name if hash[vmn] then - result[#result+1] = v + nofresult = nofresult + 1 + result[nofresult] = v end end end elseif criterium == variables.current then for i=1,#collected do local v = collected[i] - local sectionnumber = jobsections.collected[v.references.section] + local sectionnumber = sections.collected[v.references.section] if sectionnumber then local cnumbers = sectionnumber.numbers if prevmode then @@ -73,7 +81,8 @@ local function filter_collected(names,criterium,number,collected,prevmode) end end if ok then - result[#result+1] = v + nofresult = nofresult + 1 + result[nofresult] = v end end else @@ -87,7 +96,8 @@ local function filter_collected(names,criterium,number,collected,prevmode) end end if ok then - result[#result+1] = v + nofresult = nofresult + 1 + result[nofresult] = v end end end @@ -96,7 +106,7 @@ local function filter_collected(names,criterium,number,collected,prevmode) elseif criterium == variables.previous then for i=1,#collected do local v = collected[i] - local sectionnumber = jobsections.collected[v.references.section] + local sectionnumber = sections.collected[v.references.section] if sectionnumber then local cnumbers = sectionnumber.numbers if (all or hash[v.metadata.name]) and #cnumbers >= depth then @@ -118,21 +128,22 @@ local function filter_collected(names,criterium,number,collected,prevmode) end end if ok then - result[#result+1] = v + nofresult = nofresult + 1 + result[nofresult] = v end end end end elseif criterium == variables["local"] then if sections.autodepth(data.numbers) == 0 then - return filter_collected(names,variables.all,number,collected,prevmode) + return filtercollected(names,variables.all,number,collected,prevmode) else - return filter_collected(names,variables.current,number,collected,prevmode) + return filtercollected(names,variables.current,number,collected,prevmode) end else -- sectionname, number -- beware, this works ok for registers 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_registers then detail = format("depth: %s, number: %s, numbers: %s, startset: %s",depth,number,concat(sections.numbers(),".",1,depth),#collected) end @@ -141,13 +152,14 @@ local function filter_collected(names,criterium,number,collected,prevmode) local v = collected[i] local r = v.references if r then - local sectionnumber = jobsections.collected[r.section] + 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) then - result[#result+1] = v + if (all or hash[metadata.name or false]) and #cnumbers >= depth and matchingtilldepth(depth,cnumbers) then + nofresult = nofresult + 1 + result[nofresult] = v end end end @@ -157,29 +169,29 @@ local function filter_collected(names,criterium,number,collected,prevmode) end if trace_registers then if detail then - logs.report("registers","criterium: %s, %s, found: %s",criterium,detail,#result) + report_registers("criterium: %s, %s, found: %s",criterium,detail,#result) else - logs.report("registers","criterium: %s, found: %s",criterium,#result) + report_registers("criterium: %s, found: %s",criterium,#result) end end return result end -jobregisters = jobregisters or { } -jobregisters.collected = jobregisters.collected or { } -jobregisters.tobesaved = jobregisters.tobesaved or { } +local tobesaved = allocate() +local collected = allocate() -jobregisters.filter_collected = filter_collected +registers.collected = collected +registers.tobesaved = tobesaved +registers.filtercollected = filtercollected -- we follow a different strategy than by lists, where we have a global -- result table; we might do that here as well but since sorting code is -- older we delay that decision -local tobesaved, collected = jobregisters.tobesaved, jobregisters.collected - local function initializer() - tobesaved, collected = jobregisters.tobesaved, jobregisters.collected - local internals = jobreferences.internals + tobesaved = registers.tobesaved + collected = registers.collected + local internals = references.internals for name, list in next, collected do local entries = list.entries for e=1,#entries do @@ -195,7 +207,7 @@ local function initializer() end end -job.register('jobregisters.collected', jobregisters.tobesaved, initializer) +job.register('structures.registers.collected', tobesaved, initializer) local function allocate(class) local d = tobesaved[class] @@ -213,7 +225,7 @@ local function allocate(class) return d end -jobregisters.define = allocate +registers.define = allocate local entrysplitter = lpeg.Ct(lpeg.splitat('+')) -- & obsolete in mkiv @@ -222,6 +234,7 @@ local tagged = { } local function preprocessentries(rawdata) local entries = rawdata.entries if entries then +--~ table.print(rawdata) local e, k = entries[1] or "", entries[2] or "" local et, kt, entryproc, pageproc if type(e) == "table" then @@ -231,7 +244,7 @@ local function preprocessentries(rawdata) et = lpegmatch(entrysplitter,e) end if type(k) == "table" then - kt = e + kt = k else pageproc, k = processor_split(k) kt = lpegmatch(entrysplitter,k) @@ -252,12 +265,10 @@ local function preprocessentries(rawdata) rawdata.processors = { entryproc, pageproc } end rawdata.entries = nil - else - rawdata.list = { { "", "" } } -- br end end -function jobregisters.store(rawdata) -- metadata, references, entries +function registers.store(rawdata) -- metadata, references, entries local data = allocate(rawdata.metadata.name).entries local references = rawdata.references references.realpage = references.realpage or 0 -- just to be sure as it can be refered to @@ -268,14 +279,14 @@ function jobregisters.store(rawdata) -- metadata, references, entries texwrite(#data) end -function jobregisters.enhance(name,n) +function registers.enhance(name,n) local r = tobesaved[name].entries[n] if r then r.references.realpage = texcount.realpageno end end -function jobregisters.extend(name,tag,rawdata) -- maybe do lastsection internally +function registers.extend(name,tag,rawdata) -- maybe do lastsection internally if type(tag) == "string" then tag = tagged[tag] end @@ -284,16 +295,22 @@ function jobregisters.extend(name,tag,rawdata) -- maybe do lastsection internall if r then local rr = r.references rr.lastrealpage = texcount.realpageno - rr.lastsection = structure.sections.currentid() + rr.lastsection = sections.currentid() if rawdata then - preprocessentries(rawdata) + if rawdata.entries then + preprocessentries(rawdata) + end for k,v in next, rawdata do if not r[k] then r[k] = v else local rk = r[k] for kk,vv in next, v do - if vv ~= "" then + if type(vv) == "table" then + if next(vv) then + rk[kk] = vv + end + elseif vv ~= "" then rk[kk] = vv end end @@ -308,28 +325,124 @@ end local compare = sorters.comparers.basic -function jobregisters.compare(a,b) +function registers.compare(a,b) local result = compare(a,b) if result ~= 0 then return result - elseif a.metadata.kind == 'entry' then -- e/f/t - local page_a, page_b = a.references.realpage, b.references.realpage - if not page_a or not page_b then - return 0 - elseif page_a < page_b then + else + local ka, kb = a.metadata.kind, b.metadata.kind + if ka == kb then + local page_a, page_b = a.references.realpage, b.references.realpage + if not page_a or not page_b then + return 0 + elseif page_a < page_b then + return -1 + elseif page_a > page_b then + return 1 + end + elseif ka == "see" then + return 1 + elseif kb == "see" then return -1 - elseif page_a > page_b then - return 1 end end return 0 end -function jobregisters.filter(data,options) - data.result = jobregisters.filter_collected(nil,options.criterium,options.number,data.entries,true) +function registers.filter(data,options) + data.result = registers.filtercollected(nil,options.criterium,options.number,data.entries,true) +end + +local seeindex = 0 + +-- meerdere loops, seewords, dan words, an seewords + +local function crosslinkseewords(result) -- all words + -- collect all seewords + local seewords = { } + for i=1,#result do + local data = result[i] + local seeword = data.seeword + if seeword then + local seetext = seeword.text + if seetext and not seewords[seetext] then + seeindex = seeindex + 1 + seewords[seetext] = seeindex + if trace_registers then + report_registers("see word %03i: %s",seeindex,seetext) + end + end + end + end + -- mark seeparents + local seeparents = { } + for i=1,#result do + local data = result[i] + local word = data.list[1] + word = word and word[1] + if word then + local seeindex = seewords[word] + if seeindex then + seeparents[word] = data + data.references.seeparent = seeindex + if trace_registers then + report_registers("see parent %03i: %s",seeindex,word) + end + end + end + end + -- mark seewords and extend sort list + for i=1,#result do + local data = result[i] + local seeword = data.seeword + if seeword then + local text = seeword.text + if text then + local seeparent = seeparents[text] + if seeparent then + local seeindex = seewords[text] + local s, ns, d, w, l = { }, 0, data.split, seeparent.split, data.list + -- trick: we influence sorting by adding fake subentries + for i=1,#d do + ns = ns + 1 + s[ns] = d[i] -- parent + end + for i=1,#w do + ns = ns + 1 + s[ns] = w[i] -- see + end + data.split = s + -- we also register a fake extra list entry so that the + -- collapser works okay + l[#l+1] = { text, "" } + data.references.seeindex = seeindex + if trace_registers then + report_registers("see crosslink %03i: %s",seeindex,text) + end + end + end + end + end +end + +local function removeemptyentries(result) + local i, n, m = 1, #result, 0 + while i <= n do + local entry = result[i] + if #entry.list == 0 or #entry.split == 0 then + remove(result,i) + n = n - 1 + m = m + 1 + else + i = i + 1 + end + end + if m > 0 then + report_registers("%s empty entries removed in register",m) + end end -function jobregisters.prepare(data) +function registers.prepare(data) -- data has 'list' table local strip = sorters.strip local splitter = sorters.splitters.utf @@ -350,75 +463,85 @@ function jobregisters.prepare(data) end entry.split = split end + removeemptyentries(result) + crosslinkseewords(result) end end -function jobregisters.sort(data,options) - sorters.sort(data.result,jobregisters.compare) +function registers.sort(data,options) + sorters.sort(data.result,registers.compare) end -function jobregisters.unique(data,options) - local result, prev, equal = { }, nil, table.are_equal +function registers.unique(data,options) + local result, nofresult, prev = { }, 0, nil local dataresult = data.result for k=1,#dataresult do local v = dataresult[k] - if not prev then - result[#result+1], prev = v, v - else + if prev then local pr, vr = prev.references, v.references if not equal(prev.list,v.list) then - result[#result+1], prev = v, v + -- ok elseif pr.realpage ~= vr.realpage then - result[#result+1], prev = v, v + -- ok else local pl, vl = pr.lastrealpage, vr.lastrealpage if pl or vl then if not vl then - result[#result+1], prev = v, v + -- ok elseif not pl then - result[#result+1], prev = v, v + -- ok elseif pl ~= vl then - result[#result+1], prev = v, v + -- ok + else + v = nil end + else + v = nil end end end + if v then + nofresult = nofresult + 1 + result[nofresult] = v + prev = v + end end data.result = result end -function jobregisters.finalize(data,options) +function registers.finalize(data,options) -- maps character to index (order) local result = data.result data.metadata.nofsorted = #result - local split, lasttag, s, d = { }, nil, nil, nil - -- maps character to index (order) + local split, nofsplit, lasttag, done, nofdone = { }, 0, nil, nil, 0 + local firstofsplit = sorters.firstofsplit for k=1,#result do local v = result[k] - local entry, tag = sorters.firstofsplit(v) + local entry, tag = firstofsplit(v) if tag ~= lasttag then if trace_registers then - logs.report("registers","splitting at %s",tag) + report_registers("splitting at %s",tag) end - d = { } - s = { tag = tag, data = d } - split[#split+1] = s + done, nofdone = { }, 0 + nofsplit = nofsplit + 1 + split[nofsplit] = { tag = tag, data = done } lasttag = tag end - d[#d+1] = v + nofdone = nofdone + 1 + done[nofdone] = v end data.result = split end -function jobregisters.analysed(class,options) +function registers.analyzed(class,options) local data = collected[class] if data and data.entries then options = options or { } - sorters.setlanguage(options.language) - jobregisters.filter(data,options) -- filter entries into results (criteria) - jobregisters.prepare(data,options) -- adds split table parallel to list table - jobregisters.sort(data,options) -- sorts results - jobregisters.unique(data,options) -- get rid of duplicates - jobregisters.finalize(data,options) -- split result in ranges + sorters.setlanguage(options.language,options.method,options.numberorder) + registers.filter(data,options) -- filter entries into results (criteria) + registers.prepare(data,options) -- adds split table parallel to list table + registers.sort(data,options) -- sorts results + registers.unique(data,options) -- get rid of duplicates + registers.finalize(data,options) -- split result in ranges data.metadata.sorted = true return data.metadata.nofsorted or 0 else @@ -428,267 +551,251 @@ end -- todo take conversion from index -function jobregisters.userdata(index,name) - local data = jobreferences.internals[tonumber(index)] +function registers.userdata(index,name) + local data = references.internals[tonumber(index)] data = data and data.userdata and data.userdata[name] if data then - texsprint(ctxcatcodes,data) + context(data) end end --- proc can be wrapped +-- todo: ownnumber -function jobregisters.flush(data,options,prefixspec,pagespec) - local equal = table.are_equal - texsprint(ctxcatcodes,"\\startregisteroutput") - local collapse_singles = options.compress == interfaces.variables.yes - local collapse_ranges = options.compress == interfaces.variables.all - local result = data.result - -- todo ownnumber - local function pagenumber(entry) - local er = entry.references - texsprint(ctxcatcodes,format("\\registeronepage{%s}{%s}{",er.internal or 0,er.realpage or 0)) -- internal realpage content - local proc = entry.processors and entry.processors[2] - if proc then - texsprint(ctxcatcodes,"\\applyprocessor{",proc,"}{") - helpers.prefixpage(entry,prefixspec,pagespec) - texsprint(ctxcatcodes,"}") - else - helpers.prefixpage(entry,prefixspec,pagespec) - end - texsprint(ctxcatcodes,"}") - end - local function pagerange(f_entry,t_entry,is_last) - local er = f_entry.references - texsprint(ctxcatcodes,format("\\registerpagerange{%s}{%s}{",er.internal or 0,er.realpage or 0)) - local proc = f_entry.processors and f_entry.processors[2] - if proc then - texsprint(ctxcatcodes,"\\applyprocessor{",proc,"}{") - helpers.prefixpage(f_entry,prefixspec,pagespec) - texsprint(ctxcatcodes,"}") - else +local function pagerange(f_entry,t_entry,is_last,prefixspec,pagespec) + local fer, ter = f_entry.references, t_entry.references + context.registerpagerange( + f_entry.processors and f_entry.processors[2] or "", + fer.internal or 0, + fer.realpage or 0, + function() helpers.prefixpage(f_entry,prefixspec,pagespec) - end - local er = t_entry.references - texsprint(ctxcatcodes,format("}{%s}{%s}{",er.internal or 0,er.lastrealpage or er.realpage or 0)) - if is_last then - if proc then - texsprint(ctxcatcodes,"\\applyprocessor{",proc,"}{") + end, + ter.internal or 0, + ter.lastrealpage or ter.realpage or 0, + function() + if is_last then helpers.prefixlastpage(t_entry,prefixspec,pagespec) -- swaps page and realpage keys - texsprint(ctxcatcodes,"}") else - helpers.prefixlastpage(t_entry,prefixspec,pagespec) -- swaps page and realpage keys + helpers.prefixpage (t_entry,prefixspec,pagespec) end - else - if proc then - texsprint(ctxcatcodes,"\\applyprocessor{",proc,"}{") - helpers.prefixpage(t_entry,prefixspec,pagespec) - texsprint(ctxcatcodes,"}") - else - helpers.prefixpage(t_entry,prefixspec,pagespec) + end + ) +end + +local function pagenumber(entry,prefixspec,pagespec) + local er = entry.references + context.registeronepage( + entry.processors and entry.processors[2] or "", + er.internal or 0, + er.realpage or 0, + function() helpers.prefixpage(entry,prefixspec,pagespec) end + ) +end + +local function collapsedpage(pages) + for i=2,#pages do + local first, second = pages[i-1], pages[i] + local first_first, first_last, second_first, second_last = first[1], first[2], second[1], second[2] + local first_last_pn = first_last .references.realpage + local second_first_pn = second_first.references.realpage + local second_last_pn = second_last .references.realpage + local first_last_last = first_last .references.lastrealpage + local second_first_last = second_first.references.lastrealpage + if first_last_last then + first_last_pn = first_last_last + if second_first == second_last and second_first_pn <= first_last_pn then + -- 2=8, 5 -> 12=8 + remove(pages,i) + return true + elseif second_first == second_last and second_first_pn > first_last_pn then + -- 2=8, 9 -> 2-9 + pages[i-1] = { first_first, second_last } + remove(pages,i) + return true + elseif second_last_pn < first_last_pn then + -- 2=8, 3-4 -> 2=8 + remove(pages,i) + return true + elseif first_last_pn < second_last_pn then + -- 2=8, 3-9 -> 2-9 + pages[i-1] = { first_first, second_last } + remove(pages,i) + return true + elseif first_last_pn + 1 == second_first_pn and second_last_pn > first_last_pn then + -- 2=8, 9-11 -> 2-11 + pages[i-1] = { first_first, second_last } + remove(pages,i) + return true + elseif second_first.references.lastrealpage then + -- 2=8, 9=11 -> 2-11 + pages[i-1] = { first_first, second_last } + remove(pages,i) + return true + end + elseif second_first_last then + second_first_pn = second_first_last + if first_last_pn == second_first_pn then + -- 2-4, 5=9 -> 2-9 + pages[i-1] = { first_first, second_last } + remove(pages,i) + return true end + elseif first_last_pn == second_first_pn then + -- 2-3, 3-4 -> 2-4 + pages[i-1] = { first_last, second_last } + remove(pages,i) + return true end - texsprint(ctxcatcodes,"}") end - -- ranges need checking ! + return false +end + +local function collapsepages(pages) + while collapsedpage(pages) do end + return #pages +end + +function registers.flush(data,options,prefixspec,pagespec) + local collapse_singles = options.compress == variables.yes + local collapse_ranges = options.compress == variables.all + local result = data.result + context.startregisteroutput() for i=1,#result do + -- ranges need checking ! local sublist = result[i] local done = { false, false, false, false } local data = sublist.data local d, n = 0, 0 - texsprint(ctxcatcodes,format("\\startregistersection{%s}",sublist.tag)) + context.startregistersection(sublist.tag) + for d=1,#data do + local entry = data[d] + if entry.metadata.kind == "see" then + local list = entry.list + if #list > 1 then + list[#list] = nil + else + -- we have an \seeindex{Foo}{Bar} without Foo being defined anywhere + report_registers("invalid see entry in register '%s', reference '%s'", + entry.metadata.name or "?",list[1][1] or "?") + end + end + end while d < #data do d = d + 1 local entry = data[d] local e = { false, false, false, false } local metadata = entry.metadata + local kind = metadata.kind + local list = entry.list for i=1,4 do -- max 4 - if entry.list[i] then - e[i] = entry.list[i][1] + if list[i] then + e[i] = list[i][1] end if e[i] ~= done[i] then if e[i] and e[i] ~= "" then done[i] = e[i] if n == i then - texsprint(ctxcatcodes,format("\\stopregisterentries\\startregisterentries{%s}",n)) + context.stopregisterentries() + context.startregisterentries(n) else while n > i do n = n - 1 - texsprint(ctxcatcodes,"\\stopregisterentries") + context.stopregisterentries() end while n < i do n = n + 1 - texsprint(ctxcatcodes,format("\\startregisterentries{%s}",n)) + context.startregisterentries(n) end end + local internal = entry.references.internal or 0 + local seeparent = entry.references.seeparent or "" + local processor = entry.processors and entry.processors[1] or "" if metadata then - texsprint(ctxcatcodes,"\\registerentry{") - local proc = entry.processors and entry.processors[1] - if proc then - texsprint(ctxcatcodes,"\\applyprocessor{",proc,"}{") - helpers.title(e[i],metadata) - texsprint(ctxcatcodes,"}") - else - helpers.title(e[i],metadata) - end - texsprint(ctxcatcodes,"}") - else - local proc = entry.processors and entry.processors[1] - if proc then - texsprint(ctxcatcodes,"\\applyprocessor{",proc,"}{") - texsprint(ctxcatcodes,format("\\registerentry{%s}",e[i])) - texsprint(ctxcatcodes,"}") - else - texsprint(ctxcatcodes,format("\\registerentry{%s}",e[i])) - end + context.registerentry(processor,internal,seeparent,function() helpers.title(e[i],metadata) end) + else -- ? + context.registerentry(processor,internal,seeindex,e[i]) end else done[i] = false end end end - local kind = entry.metadata.kind if kind == 'entry' then - texsprint(ctxcatcodes,"\\startregisterpages") - --~ collapse_ranges = true + context.startregisterpages() if collapse_singles or collapse_ranges then -- we collapse ranges and keep existing ranges as they are -- so we get prebuilt as well as built ranges - local first, last, prev = entry, nil, entry - local pages = { } - local dd = d + local first, last, prev, pages, dd, nofpages = entry, nil, entry, { }, d, 0 while dd < #data do dd = dd + 1 local next = data[dd] - local el, nl = entry.list, next.list - if not equal(el,nl) then + if next and next.metadata.kind == "see" then dd = dd - 1 - --~ first = nil break - elseif next.references.lastrealpage then - if first then - pages[#pages+1] = { first, last or first } + else + local el, nl = entry.list, next.list + if not equal(el,nl) then + dd = dd - 1 + --~ first = nil + break + elseif next.references.lastrealpage then + nofpages = nofpages + 1 + pages[nofpages] = first and { first, last or first } or { entry, entry } + nofpages = nofpages + 1 + pages[nofpages] = { next, next } + first, last, prev = nil, nil, nil + elseif not first then + first, prev = next, next + elseif next.references.realpage - prev.references.realpage == 1 then -- 1 ? + last, prev = next, next else - pages[#pages+1] = { entry, entry } + nofpages = nofpages + 1 + pages[nofpages] = { first, last or first } + first, last, prev = next, nil, next end - pages[#pages+1] = { next, next } - first, last, prev = nil, nil, nil - elseif not first then - first, prev = next, next - elseif next.references.realpage - prev.references.realpage == 1 then -- 1 ? - last, prev = next, next - else - pages[#pages+1] = { first, last or first } - first, last, prev = next, nil, next end end if first then - pages[#pages+1] = { first, last or first } + nofpages = nofpages + 1 + pages[nofpages] = { first, last or first } end - if collapse_ranges and #pages > 1 then - -- ok, not that efficient - local function doit() - local function bubble(i) - for j=i,#pages-1 do - pages[j] = pages[j+1] - end - pages[#pages] = nil - end - for i=2,#pages do - local first, second = pages[i-1], pages[i] - local first_first, first_last, second_first, second_last = first[1], first[2], second[1], second[2] - local first_last_pn = first_last .references.realpage - local second_first_pn = second_first.references.realpage - local second_last_pn = second_last .references.realpage - local first_last_last = first_last .references.lastrealpage - local second_first_last = second_first.references.lastrealpage - if first_last_last then - first_last_pn = first_last_last - if second_first == second_last and second_first_pn <= first_last_pn then - -- 2=8, 5 -> 12=8 - bubble(i) - return true - elseif second_first == second_last and second_first_pn > first_last_pn then - -- 2=8, 9 -> 2-9 - pages[i-1] = { first_first, second_last } - bubble(i) - return true - elseif second_last_pn < first_last_pn then - -- 2=8, 3-4 -> 2=8 - bubble(i) - return true - elseif first_last_pn < second_last_pn then - -- 2=8, 3-9 -> 2-9 - pages[i-1] = { first_first, second_last } - bubble(i) - return true - elseif first_last_pn + 1 == second_first_pn and second_last_pn > first_last_pn then - -- 2=8, 9-11 -> 2-11 - pages[i-1] = { first_first, second_last } - bubble(i) - return true - elseif second_first.references.lastrealpage then - -- 2=8, 9=11 -> 2-11 - pages[i-1] = { first_first, second_last } - bubble(i) - return true - end - elseif second_first_last then - second_first_pn = second_first_last - if first_last_pn == second_first_pn then - -- 2-4, 5=9 -> 2-9 - pages[i-1] = { first_first, second_last } - bubble(i) - return true - end - elseif first_last_pn == second_first_pn then - -- 2-3, 3-4 -> 2-4 - pages[i-1] = { first_last, second_last } - bubble(i) - return true - end - end - return false - end - while doit() do end + if collapse_ranges and nofpages > 1 then + nofpages = collapsepages(pages) end - -- - if #pages > 0 then -- or 0 + if nofpages > 0 then -- or 0 d = dd - for p=1,#pages do + for p=1,nofpages do local first, last = pages[p][1], pages[p][2] if first == last then if first.references.lastrealpage then - pagerange(first,first,true) + pagerange(first,first,true,prefixspec,pagespec) else - pagenumber(first) + pagenumber(first,prefixspec,pagespec) end elseif last.references.lastrealpage then - pagerange(first,last,true) + pagerange(first,last,true,prefixspec,pagespec) else - pagerange(first,last,false) + pagerange(first,last,false,prefixspec,pagespec) end end + elseif entry.references.lastrealpage then + pagerange(entry,entry,true,prefixspec,pagespec) else - if entry.references.lastrealpage then - pagerange(entry,entry,true) - else - pagenumber(entry) - end + pagenumber(entry,prefixspec,pagespec) end else while true do if entry.references.lastrealpage then - pagerange(entry,entry,true) + pagerange(entry,entry,true,prefixspec,pagespec) else - pagenumber(entry) + pagenumber(entry,prefixspec,pagespec) end if d == #data then break else d = d + 1 local next = data[d] - if not equal(entry.list,next.list) then + if next.metadata.kind == "see" or not equal(entry.list,next.list) then d = d - 1 break else @@ -697,39 +804,55 @@ function jobregisters.flush(data,options,prefixspec,pagespec) end end end - texsprint(ctxcatcodes,"\\stopregisterpages") + context.stopregisterpages() elseif kind == 'see' then - -- maybe some day more words - texsprint(ctxcatcodes,"\\startregisterseewords") - local proc = entry.processors and entry.processors[1] - if proc then - texsprint(ctxcatcodes,"\\applyprocessor{",proc,"}{") - texsprint(ctxcatcodes,format("\\registeroneword{0}{0}{%s}",entry.seeword.text)) -- todo: internal - texsprint(ctxcatcodes,"}") - else - texsprint(ctxcatcodes,format("\\registeroneword{0}{0}{%s}",entry.seeword.text)) -- todo: internal + local t, nt = { }, 0 + while true do + nt = nt + 1 + t[nt] = entry + if d == #data then + break + else + d = d + 1 + local next = data[d] + if next.metadata.kind ~= "see" or not equal(entry.list,next.list) then + d = d - 1 + break + else + entry = next + end + end end - texsprint(ctxcatcodes,"\\stopregisterseewords") + context.startregisterseewords() + for i=1,nt do + local entry = t[i] + local processor = entry.processors and entry.processors[1] or "" + local seeindex = entry.references.seeindex or "" + local seeword = entry.seeword.text or "" + context.registerseeword(i,n,processor,0,seeindex,seeword) + end + context.stopregisterseewords() end end while n > 0 do - texsprint(ctxcatcodes,"\\stopregisterentries") + context.stopregisterentries() n = n - 1 end - texsprint(ctxcatcodes,"\\stopregistersection") + context.stopregistersection() end - texsprint(ctxcatcodes,"\\stopregisteroutput") + context.stopregisteroutput() -- for now, maybe at some point we will do a multipass or so data.result = nil data.metadata.sorted = false end -function jobregisters.analyse(class,options) - texwrite(jobregisters.analysed(class,options)) +function registers.analyze(class,options) + texwrite(registers.analyzed(class,options)) end -function jobregisters.process(class,...) - if jobregisters.analysed(class,...) > 0 then - jobregisters.flush(collected[class],...) +function registers.process(class,...) + if registers.analyzed(class,...) > 0 then + registers.flush(collected[class],...) end end + |