diff options
author | Context Git Mirror Bot <phg42.2a@gmail.com> | 2014-11-12 12:15:04 +0100 |
---|---|---|
committer | Context Git Mirror Bot <phg42.2a@gmail.com> | 2014-11-12 12:15:04 +0100 |
commit | 412796f51a6c4e721018f37242013d62d7d82ad6 (patch) | |
tree | 4ac15cbfc2d333c5de9a129434a410f9afca7e5f /tex/context/base/publ-ini.lua | |
parent | d26cacc03e700db6a15cefab13fe3b007c416325 (diff) | |
download | context-412796f51a6c4e721018f37242013d62d7d82ad6.tar.gz |
2014-11-12 11:58:00
Diffstat (limited to 'tex/context/base/publ-ini.lua')
-rw-r--r-- | tex/context/base/publ-ini.lua | 3248 |
1 files changed, 1619 insertions, 1629 deletions
diff --git a/tex/context/base/publ-ini.lua b/tex/context/base/publ-ini.lua index 188995b0a..b7f164610 100644 --- a/tex/context/base/publ-ini.lua +++ b/tex/context/base/publ-ini.lua @@ -6,6 +6,9 @@ if not modules then modules = { } end modules ['publ-ini'] = { license = "see context related readme files" } +-- bah .. this 200 locals limit again ... so we need to split it as adding more +-- do ... ends makes it messier + -- plug the list sorted in the list mechanism (specification.sortorder) -- todo: delay details till alternative is known so that potential author @@ -18,7 +21,7 @@ if not modules then modules = { } end modules ['publ-ini'] = { -- load big bib files many times and even then ... fonts are larger. local next, rawget, type, tostring, tonumber = next, rawget, type, tostring, tonumber -local match, gmatch, format, gsub, find = string.match, string.gmatch, string.format, string.gsub, string.find +local match, find = string.match, string.find local concat, sort, tohash = table.concat, table.sort, table.tohash local utfsub = utf.sub local mod = math.mod @@ -38,10 +41,15 @@ local trace = false trackers.register("publications", local trace_cite = false trackers.register("publications.cite", function(v) trace_cite = v end) local trace_missing = false trackers.register("publications.cite.missing", function(v) trace_missing = v end) local trace_references = false trackers.register("publications.cite.references", function(v) trace_references = v end) +local trace_detail = false trackers.register("publications.detail", function(v) trace_detail = v end) publications = publications or { } local datasets = publications.datasets local writers = publications.writers +local casters = publications.casters +local detailed = publications.detailed +local enhancer = publications.enhancer +local enhancers = publications.enhancers local tracers = publications.tracers or { } publications.tracers = tracers @@ -162,17 +170,12 @@ function commands.registerbtxlistvariant(name,parent) registeredlistvariants[name] = parent or "" end -local specifications = publications.specifications -local currentspecification = specifications[false] ------ currentspecificationfields = currentspecification.fields -local currentspecificationcategories = currentspecification.categories - -local ignoredfields = { } +local specifications = publications.specifications +local currentspecification = specifications[false] +local ignoredfields = { } local function setspecification(name) - currentspecification = specifications[name] - -- currentspecificationfields = currentspecification.fields - currentspecificationcategories = currentspecification.categories + currentspecification = specifications[name] if trace then report("setting specification %a",type(name) == "string" and name or "anything") end @@ -238,9 +241,6 @@ end) local collected = allocate() local tobesaved = allocate() --- we use a a dedicated (and efficient as it know what it deals with) serializer, --- also because we need to ignore the 'details' field - do local function serialize(t) @@ -312,7 +312,11 @@ do if datasources then for i=1,#datasources do local filename = datasources[i].filename - publications.load(dataset,filename,"previous") + publications.load { + dataset = dataset, + filename = filename, + kind = "previous" + } end end if usersource then @@ -327,21 +331,19 @@ do end -if not publications.authors then - initializer() -- for now, runtime loaded -end - -- we want to minimize references as there can be many (at least -- when testing) -local initialized = false -local usedentries = allocate { } -local citetolist = allocate { } -local listtocite = allocate { } local nofcitations = 0 +local usedentries = nil +local citetolist = nil +local listtocite = nil -setmetatableindex(usedentries,function(t,k) - if not initialized then +do + + local initialize = nil + + initialize = function(t) usedentries = allocate { } citetolist = allocate { } listtocite = allocate { } @@ -434,12 +436,20 @@ setmetatableindex(usedentries,function(t,k) end end end - return usedentries[k] + initialize = nil + end + + usedentries = setmetatableindex(function(_,k) if initialize then initialize() end return usedentries[k] end) + citetolist = setmetatableindex(function(_,k) if initialize then initialize() end return citetolist [k] end) + listtocite = setmetatableindex(function(_,k) if initialize then initialize() end return listtocite [k] end) + + function publications.usedentries() + if initialize then + initialize() + end + return usedentries end -end) -function publications.usedentries(dataset) - return usedentries[dataset] end -- match: @@ -451,103 +461,108 @@ end -- by prefix -- by dataset -local reported = { } -local finder = publications.finder - -local function findallused(dataset,reference,internal) - local finder = publications.finder -- for the moment, not yet in all betas - local find = finder and finder(reference) - local tags = not find and settings_to_array(reference) - local todo = { } - local okay = { } -- only if mark - local set = usedentries[dataset] - local valid = datasets[dataset].luadata - local ordered = datasets[dataset].ordered - if set then - local function register(tag) - local entry = set[tag] - if entry then - -- only once in a list but at some point we can have more (if we - -- decide to duplicate) - if #entry == 1 then - entry = entry[1] - else - -- same block and section - local done = false - if internal and internal > 0 then - -- first following in list - for i=1,#entry do - local e = entry[i] - if e.references.internal > internal then - done = e - break - end - end - if not done then - -- last preceding in list +local findallused do + + local reported = { } + local finder = publications.finder + + findallused = function(dataset,reference,internal) + local finder = publications.finder -- for the moment, not yet in all betas + local find = finder and finder(reference) + local tags = not find and settings_to_array(reference) + local todo = { } + local okay = { } -- only if mark + local set = usedentries[dataset] + local current = datasets[dataset] + local valid = current.luadata + local ordered = current.ordered + if set then + local function register(tag) + local entry = set[tag] + if entry then + -- only once in a list but at some point we can have more (if we + -- decide to duplicate) + if #entry == 1 then + entry = entry[1] + else + -- same block and section + local done = false + if internal and internal > 0 then + -- first following in list for i=1,#entry do local e = entry[i] - if e.references.internal < internal then + if e.references.internal > internal then done = e - else break end end + if not done then + -- last preceding in list + for i=1,#entry do + local e = entry[i] + if e.references.internal < internal then + done = e + else + break + end + end + end + end + if done then + entry = done + else + entry = entry[1] end end - if done then - entry = done - else - entry = entry[1] - end - end - okay[#okay+1] = entry - end - todo[tag] = true - end - if find then - tags = { } - for i=1,#ordered do - local entry = ordered[i] - if find(entry) then - local tag = entry.tag - register(tag) - tags[#tags+1] = tag + okay[#okay+1] = entry end + todo[tag] = true end - else - for i=1,#tags do - local tag = tags[i] - if valid[tag] then - register(tag) - elseif not reported[tag] then - reported[tag] = true - report_cite("non-existent entry %a in %a",tag,dataset) + if find then + tags = { } + for i=1,#ordered do + local entry = ordered[i] + if find(entry) then + local tag = entry.tag + register(tag) + tags[#tags+1] = tag + end end - end - end - else - if find then - tags = { } - for i=1,#ordered do - local entry = ordered[i] - if find(entry) then - tags[#tags+1] = entry.tag + else + for i=1,#tags do + local tag = tags[i] + if valid[tag] then + register(tag) + elseif not reported[tag] then + reported[tag] = true + report_cite("non-existent entry %a in %a",tag,dataset) + end end end else - for i=1,#tags do - local tag = tags[i] - if valid[tag] then - todo[tag] = true - elseif not reported[tag] then - reported[tag] = true - report_cite("non-existent entry %a in %a",tag,dataset) + if find then + tags = { } + for i=1,#ordered do + local entry = ordered[i] + if find(entry) then + tags[#tags+1] = entry.tag + end + end + else + for i=1,#tags do + local tag = tags[i] + if valid[tag] then + todo[tag] = true + elseif not reported[tag] then + reported[tag] = true + report_cite("non-existent entry %a in %a",tag,dataset) + end end end end + return okay, todo, tags end - return okay, todo, tags + end local function unknowncite(reference) @@ -671,201 +686,132 @@ end -- basic loading -function commands.usebtxdataset(name,filename) - publications.load(datasets[name],filename,"current") +function commands.usebtxdataset(specification) + specification.kind = "current" + publications.load(specification) end function commands.convertbtxdatasettoxml(name,nice) - publications.converttoxml(datasets[name],nice) + publications.converttoxml(name,nice) end -- enhancing -local splitauthorstring = publications.authors.splitstring - -local pagessplitter = lpeg.splitat(P("-")^1) - --- maybe not redo when already done +do -local function shortsorter(a,b) - local ay, by = a[2], b[2] - if ay ~= by then - return ay < by - end - local ay, by = a[3], b[3] - if ay ~= by then - return ay < by - end - return a[4] < b[4] -end + -- maybe not redo when already done -function publications.enhance(dataset) -- for the moment split runs (maybe publications.enhancers) - statistics.starttiming(publications) - if type(dataset) == "string" then - dataset = datasets[dataset] - else - -- assume table, otherwise maybe issue an error - end - local used = usedentries[dataset.name] or { } - local luadata = dataset.luadata - local details = dataset.details - local ordered = dataset.ordered - local types = currentspecification.types -- or { author = "author", editor = "author" } - local authors = { } - -- - for k, v in next, types do - if v == "author" then - authors[#authors+1] = k + local function shortsorter(a,b) + local ay, by = a[2], b[2] + if ay ~= by then + return ay < by end - end - -- - for tag, entry in next, luadata do - local detail = { } - details[tag] = detail - for i=1,#authors do - local key = authors[i] - local value = entry[key] - if value then - detail[key] = splitauthorstring(value) - end + local ay, by = a[3], b[3] + if ay ~= by then + return ay < by end + return a[4] < b[4] end - -- short - local shorts = { } - for i=1,#ordered do - local entry = ordered[i] - if entry then - local tag = entry.tag - if tag then - local detail = details[tag] - if detail then - local author = detail.author - if author then - -- number depends on sort order - local t = { } - if #author == 0 then - -- what - else - local n = #author == 1 and 3 or 1 - for i=1,#author do - local surnames = author[i].surnames - if not surnames or #surnames == 0 then - -- error + + -- We could avoid loops by combining enhancers but that makes it only + -- more messy and for documents that use publications the few extra milli + -- seconds are irrelevant (there is for sure more to gain by proper coding + -- of the source and or style). + + function publications.enhancers.suffixes(dataset) + local used = usedentries[dataset.name] + local luadata = dataset.luadata + local details = dataset.details + local ordered = dataset.ordered + local caster = casters.author + local getter = publications.directget + local shorts = { } + for i=1,#ordered do + local entry = ordered[i] + if entry then + local tag = entry.tag + if tag then + local use = used[tag] + if use then + -- use is a table of used list entries (so there can be more) and we just look at + -- the first one for btx properties + local listentry = use[1] + local userdata = listentry.userdata + local btxspc = userdata and userdata.btxspc + if btxspc then + local author = getter(dataset,entry,"author",specifications[btxspc]) + if author then + author = caster(author) + -- number depends on sort order + local t = { } + if #author > 0 then + local n = #author == 1 and 3 or 1 + for i=1,#author do + local surnames = author[i].surnames + if not surnames or #surnames == 0 then + -- error + else + t[#t+1] = utfsub(surnames[1],1,n) + end + end + end + local year = tonumber(entry.year) or 0 + local short = formatters["%t%02i"](t,mod(year,100)) + local s = shorts[short] + -- we could also sort on reference i.e. entries.text + if u then + u = listentry.entries.text -- hm + else + u = "0" + end + if not s then + shorts[short] = { { tag, year, u, i } } else - t[#t+1] = utfsub(surnames[1],1,n) + s[#s+1] = { tag, year, u, i } end end - end - local year = tonumber(entry.year) or 0 - local short = formatters["%t%02i"](t,mod(year,100)) - local s = shorts[short] - -- we could also sort on reference i.e. entries.text - local u = used[tag] - if u then - u = u[1].entries.text -- hm else - u = "0" + --- no spec so let's forget about it end - if not s then - shorts[short] = { { tag, year, u, i } } - else - s[#s+1] = { tag, year, u, i } - end - else - -- end - else - report("internal error, no detail for tag %s",tag) - end - -- - local pages = entry.pages or entry.page - if pages then - local first, last = lpegmatch(pagessplitter,pages) - detail.pages = first and last and { first, last } or pages - end - -- - local keyword = entry.keyword - if keyword then - detail.keyword = settings_to_set(keyword) end - -- - if category == "inbook" then - detail.maintitle = entry.chapter or entry.title - elseif category == "incollection" then - detail.maintitle = entry.title or entry.booktitle - else - detail.maintitle = entry.title or entry.chapter or entry.booktitle - end - else - report("internal error, no tag at index %s",i) end - else - report("internal error, no entry at index %s",i) - end - end - for short, tags in next, shorts do -- ordered ? - local done = #tags > 0 - -- we only use suffixes when there are multiple references to same years - -- so we check for used first - if done then - local n = 0 - for i=1,#tags do - local tag = tags[i][1] - if used[tag] then - n = n + 1 - if n > 1 then - break + end + for short, tags in next, shorts do -- ordered ? + local done = #tags > 0 + -- now we assign the suffixes, unless we have only one reference + if done then + sort(tags,shortsorter) + local n = #tags + if n > 1 then + for i=1,n do + local tag = tags[i][1] + local detail = details[tag] + local suffix = numbertochar(i) + local entry = luadata[tag] + local year = entry.year + detail.short = short + detail.suffix = suffix + if year then + detail.suffixedyear = year .. suffix + end end end - end - done = n > 1 - end - -- now we assign the suffixes, unless we have only one reference - if done then - sort(tags,shortsorter) - local n = 0 - for i=1,#tags do - local tag = tags[i][1] + else + local tag = tags[1][1] local detail = details[tag] + local entry = luadata[tag] + local year = entry.year detail.short = short - if used[tag] then - n = n + 1 - local suffix = numbertochar(n) - detail.suffix = suffix - local entry = luadata[tag] - local year = entry.year - if year then - detail.suffixedyear = year .. suffix - end + if year then + detail.suffixedyear = year end end - -- for i=1,#tags do - -- local tag = tags[i][1] - -- local detail = details[tag] - -- if not detail.suffix then - -- n = n + 1 - -- local suffix = numbertochar(n) - -- detail.suffix = suffix - -- local entry = luadata[tag] - -- local year = entry.year - -- if year then - -- detail.suffixedyear = year .. suffix - -- end - -- end - -- end - else - local tag = tags[1][1] - local detail = details[tag] - detail.short = short - local entry = luadata[tag] - local year = entry.year - if year then - detail.suffixedyear = year - end end end - dataset.enhanced = true - statistics.stoptiming(publications) + + utilities.sequencers.appendaction(enhancer,"system","publications.enhancers.suffixes") + end function commands.addbtxentry(name,settings,content) @@ -940,23 +886,28 @@ do -- when we have a special kind of database local function permitted(category,field) - local catspec = currentspecificationcategories[category] + local catspec = currentspecification.categories[category] if not catspec then - report("invalid category %a, %s",category,"no specification") + report("invalid category %a, %s",category,"no specification") -- can't happen return false end local fields = catspec.fields if not fields then - report("invalid category %a, %s",category,"no fields") + report("invalid category %a, %s",category,"no fields") -- can't happen return false end - local kind = fields[field] if ignoredfields and ignoredfields[field] then return false - else - --- just "return true" as it's already in fields - local sets = catspec.sets - return sets and sets[field] or true + end + local sets = catspec.sets + if sets then + local set = sets[field] + if set then + return set + end + end + if fields[field] then + return true end end @@ -968,36 +919,36 @@ do return field, okay end local details = dataset.details[tag] - local okay = details[field] - if okay then - return field, okay + local value = details[field] + if value then + return field, value end elseif valid then -- local fields = dataset.luadata[tag] for i=1,#valid do local field = valid[i] - local okay = fields[field] - if okay then - return field, okay + local value = fields[field] + if value then + return field, value end end local details = dataset.details[tag] for i=1,#valid do - local okay = details[field] - if okay then - return field, okay + local value = details[field] + if value then + return field, value end end end end - local function get(name,tag,field,what,check) - local dataset = rawget(datasets,name) + local function get(dataset,tag,field,what,check,catspec) + dataset = rawget(datasets,name) if dataset then local data = dataset.luadata[tag] if data then local category = data.category - local catspec = currentspecificationcategories[category] + local catspec = (catspec or currentspecification).categories[category] if not catspec then return false end @@ -1036,6 +987,32 @@ do return "" end + publications.get = get + + function publications.directget(dataset,data,field,catspec) + local catspec = (catspec or currentspecification).categories[data.category] + if not catspec then + return false + end + local fields = catspec.fields + if fields then + local sets = catspec.sets + if sets then + local set = sets[field] + if set then + for i=1,#set do + local field = set[i] + local value = fields[field] and data[field] -- redundant check + if value then + return value + end + end + end + end + return fields[field] and data[field] or nil -- redundant check + end + end + function commands.btxfieldname(name,tag,field) context(get(name,tag,field,false,false)) end function commands.btxfieldtype(name,tag,field) context(get(name,tag,field,true, false)) end function commands.btxfoundname(name,tag,field) context(get(name,tag,field,false,true )) end @@ -1053,10 +1030,10 @@ do local name, value = found(dataset,tag,field,valid,fields) if value then typesetters[currentspecification.types[name]](field,value,manipulator) - else + elseif trace_detail then report("%s %s %a in category %a for tag %a in dataset %a","unknown","entry",field,category,tag,name) end - else + elseif trace_detail then report("%s %s %a in category %a for tag %a in dataset %a","invalid","entry",field,category,tag,name) end else @@ -1078,10 +1055,10 @@ do local value = fields[field] if value then typesetters[currentspecification.types[field]](field,value,manipulator) - else + elseif trace_detail then report("%s %s %a in category %a for tag %a in dataset %a","unknown","field",field,category,tag,name) end - else + elseif trace_detail then report("%s %s %a in category %a for tag %a in dataset %a","invalid","field",field,category,tag,name) end else @@ -1105,10 +1082,10 @@ do local value = details[field] if value then typesetters[currentspecification.types[field]](field,value,manipulator) - else + elseif trace_detail then report("%s %s %a in category %a for tag %a in dataset %a","unknown","detail",field,category,tag,name) end - else + elseif trace_detail then report("%s %s %a in category %a for tag %a in dataset %a","invalid","detail",field,category,tag,name) end else @@ -1157,392 +1134,410 @@ function publications.singularorplural(singular,plural) end end -local patterns = { "publ-imp-%s.mkvi", "publ-imp-%s.mkiv", "publ-imp-%s.tex" } +-- loading -local function failure(name) - report("unknown library %a",name) -end +do -local function action(name,foundname) - context.input(foundname) -end + local patterns = { "publ-imp-%s.mkvi", "publ-imp-%s.mkiv", "publ-imp-%s.tex" } + + local function failure(name) + report("unknown library %a",name) + end + + local function action(name,foundname) + context.input(foundname) + end + + function commands.loadbtxdefinitionfile(name) -- a more specific name + commands.uselibrary { + name = string.gsub(name,"^publ%-",""), + patterns = patterns, + action = action, + failure = failure, + onlyonce = true, + } + end -function commands.loadbtxdefinitionfile(name) -- a more specific name - commands.uselibrary { - name = gsub(name,"^publ%-",""), - patterns = patterns, - action = action, - failure = failure, - onlyonce = true, - } end --- lists: +-- lists -publications.lists = publications.lists or { } -local lists = publications.lists +do -local context = context -local structures = structures + publications.lists = publications.lists or { } + local lists = publications.lists -local references = structures.references -local sections = structures.sections + local context = context + local structures = structures --- per rendering + local references = structures.references + local sections = structures.sections -local renderings = { } --- per dataset + -- per rendering -setmetatableindex(renderings,function(t,k) - local v = { - list = { }, - done = { }, - alldone = { }, - used = { }, - registered = { }, - ordered = { }, - shorts = { }, - method = v_none, - texts = setmetatableindex("table"), - currentindex = 0, - } - t[k] = v - return v -end) + local renderings = { } --- per dataset --- helper - --- local function sortedtags(dataset,list,sorttype) --- local luadata = datasets[dataset].luadata --- local valid = { } --- for i=1,#list do --- local tag = list[i] --- local entry = luadata[tag] --- if entry then --- local key = entry[sorttype] --- if key then --- valid[#valid+1] = { --- tag = tag, --- split = sortsplitter(sortstripper(key)) --- } --- end --- end --- end --- if #valid == 0 or #valid ~= #list then --- return list --- else --- sorters.sort(valid,basicsorter) --- for i=1,#valid do --- valid[i] = valid[i].tag --- end --- return valid --- end --- end --- --- if sorttype and sorttype ~= "" then --- tags = sortedtags(dataset,tags,sorttype) --- end + setmetatableindex(renderings,function(t,k) + local v = { + list = { }, + done = { }, + alldone = { }, + used = { }, + registered = { }, + ordered = { }, + shorts = { }, + method = v_none, + texts = setmetatableindex("table"), + currentindex = 0, + } + t[k] = v + return v + end) --- why shorts vs tags: only for sorting + -- helper + + -- local function sortedtags(dataset,list,sorttype) + -- local luadata = datasets[dataset].luadata + -- local valid = { } + -- for i=1,#list do + -- local tag = list[i] + -- local entry = luadata[tag] + -- if entry then + -- local key = entry[sorttype] + -- if key then + -- valid[#valid+1] = { + -- tag = tag, + -- split = sortsplitter(sortstripper(key)) + -- } + -- end + -- end + -- end + -- if #valid == 0 or #valid ~= #list then + -- return list + -- else + -- sorters.sort(valid,basicsorter) + -- for i=1,#valid do + -- valid[i] = valid[i].tag + -- end + -- return valid + -- end + -- end + -- + -- if sorttype and sorttype ~= "" then + -- tags = sortedtags(dataset,tags,sorttype) + -- end -function lists.register(dataset,tag,short) -- needs checking now that we split - local r = renderings[dataset] - if not short or short == "" then - short = tag - end - if trace then - report("registering publication entry %a with shortcut %a",tag,short) + -- why shorts vs tags: only for sorting + + function lists.register(dataset,tag,short) -- needs checking now that we split + local r = renderings[dataset] + if not short or short == "" then + short = tag + end + if trace then + report("registering publication entry %a with shortcut %a",tag,short) + end + local top = #r.registered + 1 + -- do we really need these + r.registered[top] = tag + r.ordered [tag] = top + r.shorts [tag] = short end - local top = #r.registered + 1 - -- do we really need these - r.registered[top] = tag - r.ordered [tag] = top - r.shorts [tag] = short -end -function lists.nofregistered(dataset) - return #renderings[dataset].registered -end + function lists.nofregistered(dataset) + return #renderings[dataset].registered + end -local function validkeyword(dataset,tag,keyword) - local ds = datasets[dataset] - if not ds then - report("unknown dataset %a",dataset) - return - end - local dt = ds.details[tag] - if not dt then - report("no details for tag %a",tag) - return - end - local kw = dt.keyword - if kw then - for k in next, keyword do - if kw[k] then - return true + local function validkeyword(dataset,entry,keyword) + local kw = fastget(dataset,entry,"keywords") -- hard coded for the moment + if kw then + for k in next, keyword do + if kw[k] then + return true + end end end end -end -local function registerpage(pages,tag,result,listindex) - local p = pages[tag] - local r = result[listindex].references - if p then - local last = p[#p][2] - local real = last.realpage - if real ~= r.realpage then - p[#p+1] = { listindex, r } + local function registerpage(pages,tag,result,listindex) + local p = pages[tag] + local r = result[listindex].references + if p then + local last = p[#p][2] + local real = last.realpage + if real ~= r.realpage then + p[#p+1] = { listindex, r } + end + else + pages[tag] = { { listindex, r } } end - else - pages[tag] = { { listindex, r } } end -end -local methods = { } -lists.methods = methods + local methods = { } + lists.methods = methods -methods[v_dataset] = function(dataset,rendering,keyword) - -- why only once unless criterium=all? - local luadata = datasets[dataset].luadata - local list = rendering.list - for tag, data in sortedhash(luadata) do - if not keyword or validkeyword(dataset,tag,keyword) then - list[#list+1] = { tag, false, 0, false, false } + methods[v_dataset] = function(dataset,rendering,keyword) + -- why only once unless criterium=all? + local current = datasets[dataset] + local luadata = current.luadata + local list = rendering.list + for tag, data in sortedhash(luadata) do + if not keyword or validkeyword(dataset,data,keyword) then + list[#list+1] = { tag, false, 0, false, false } + end end end -end -methods[v_force] = function (dataset,rendering,keyword) - -- only for checking, can have duplicates, todo: collapse page numbers, although - -- we then also needs deferred writes - local result = structures.lists.filter(rendering.specification) or { } - local list = rendering.list - for listindex=1,#result do - local r = result[listindex] - local u = r.userdata - if u and u.btxset == dataset then - local tag = u.btxref - if tag and (not keyword or validkeyword(dataset,tag,keyword)) then - list[#list+1] = { tag, listindex, 0, u, u.btxint } + methods[v_force] = function (dataset,rendering,keyword) + -- only for checking, can have duplicates, todo: collapse page numbers, although + -- we then also needs deferred writes + local result = structures.lists.filter(rendering.specification) or { } + local list = rendering.list + local current = datasets[dataset] + local luadata = current.luadata + for listindex=1,#result do + local r = result[listindex] + local u = r.userdata + if u and u.btxset == dataset then + local tag = u.btxref + if tag and (not keyword or validkeyword(dataset,luadata[tag],keyword)) then + list[#list+1] = { tag, listindex, 0, u, u.btxint } + end end end - end - lists.result = result -end - --- local : if tag and done[tag] ~= section then ... --- global : if tag and not alldone[tag] and done[tag] ~= section then ... - -methods[v_local] = function(dataset,rendering,keyword) - local result = structures.lists.filter(rendering.specification) or { } - local section = sections.currentid() - local list = rendering.list - local repeated = rendering.repeated == v_yes - local r_done = rendering.done - local r_alldone = rendering.alldone - local done = repeated and { } or r_done - local alldone = repeated and { } or r_alldone - local doglobal = rendering.method == v_global - local traced = { } -- todo: only if interactive (backlinks) or when tracing - local pages = { } - for listindex=1,#result do - local r = result[listindex] - local u = r.userdata - if u and u.btxset == dataset then - local tag = u.btxref - if not tag then - -- problem - elseif done[tag] == section then -- a bit messy for global and all and so - -- skip - elseif doglobal and alldone[tag] then - -- skip - elseif not keyword or validkeyword(dataset,tag,keyword) then - if traced then - local l = traced[tag] - if l then - l[#l+1] = u.btxint + lists.result = result + end + + -- local : if tag and done[tag] ~= section then ... + -- global : if tag and not alldone[tag] and done[tag] ~= section then ... + + methods[v_local] = function(dataset,rendering,keyword) + local result = structures.lists.filter(rendering.specification) or { } + local section = sections.currentid() + local list = rendering.list + local repeated = rendering.repeated == v_yes + local r_done = rendering.done + local r_alldone = rendering.alldone + local done = repeated and { } or r_done + local alldone = repeated and { } or r_alldone + local doglobal = rendering.method == v_global + local traced = { } -- todo: only if interactive (backlinks) or when tracing + local pages = { } + local current = datasets[dataset] + local luadata = current.luadata + for listindex=1,#result do + local r = result[listindex] + local u = r.userdata + if u and u.btxset == dataset then + local tag = u.btxref + if not tag then + -- problem + elseif done[tag] == section then -- a bit messy for global and all and so + -- skip + elseif doglobal and alldone[tag] then + -- skip + elseif not keyword or validkeyword(dataset,luadata[tag],keyword) then + if traced then + local l = traced[tag] + if l then + l[#l+1] = u.btxint + else + local l = { tag, listindex, 0, u, u.btxint } + list[#list+1] = l + traced[tag] = l + end else - local l = { tag, listindex, 0, u, u.btxint } - list[#list+1] = l - traced[tag] = l + done[tag] = section + alldone[tag] = true + list[#list+1] = { tag, listindex, 0, u, u.btxint } end - else - done[tag] = section - alldone[tag] = true - list[#list+1] = { tag, listindex, 0, u, u.btxint } end + registerpage(pages,tag,result,listindex) end - registerpage(pages,tag,result,listindex) end - end - if traced then - for tag in next, traced do - done[tag] = section - alldone[tag] = true + if traced then + for tag in next, traced do + done[tag] = section + alldone[tag] = true + end end + lists.result = result + structures.lists.result = result + rendering.pages = pages -- or list.pages + -- inspect(pages) + end + + methods[v_global] = methods[v_local] + + function lists.collectentries(specification) + local dataset = specification.btxdataset + if not dataset then + return + end + local rendering = renderings[dataset] + if not rendering then + return + end + local method = specification.method or v_none + local ignored = specification.ignored or "" + rendering.method = method + rendering.ignored = ignored ~= "" and settings_to_set(ignored) or nil + rendering.list = { } + rendering.done = { } + rendering.sorttype = specification.sorttype or v_default + rendering.criterium = specification.criterium or v_none + rendering.repeated = specification.repeated or v_no + rendering.specification = specification + local filtermethod = methods[method] + if not filtermethod then + return + end + lists.result = { } -- kind of reset + local keyword = specification.keyword + if keyword and keyword ~= "" then + keyword = settings_to_set(keyword) + else + keyword = nil + end + filtermethod(dataset,rendering,keyword) end - lists.result = result - structures.lists.result = result - rendering.pages = pages -- or list.pages - -- inspect(pages) -end - -methods[v_global] = methods[v_local] - -function lists.collectentries(specification) - local dataset = specification.btxdataset - if not dataset then - return - end - local rendering = renderings[dataset] - if not rendering then - return - end - local method = specification.method or v_none - local ignored = specification.ignored or "" - rendering.method = method - rendering.ignored = ignored ~= "" and settings_to_set(ignored) or nil - rendering.list = { } - rendering.done = { } - rendering.sorttype = specification.sorttype or v_default - rendering.criterium = specification.criterium or v_none - rendering.repeated = specification.repeated or v_no - rendering.specification = specification - local filtermethod = methods[method] - if not filtermethod then - return - end - lists.result = { } -- kind of reset - local keyword = specification.keyword - if keyword and keyword ~= "" then - keyword = settings_to_set(keyword) - else - keyword = nil - end - filtermethod(dataset,rendering,keyword) -end - --- experiment -local splitspec = lpeg.splitat(S(":.")) -local splitter = sorters.splitters.utf -local strip = sorters.strip + -- experiment -local function newsplitter(splitter) - return setmetatableindex({},function(t,k) -- could be done in the sorter but seldom that many shared - local v = splitter(k,true) -- in other cases - t[k] = v - return v - end) -end + local splitspec = lpeg.splitat(S(":.")) + local splitter = sorters.splitters.utf + local strip = sorters.strip -local template = [[ - local strip = sorters.strip - local writers = publications.writers - return function(entry,detail,splitted,i) -- snippets - return { - index = i, - split = { %s, splitted[tostring(i)] } - } + local function newsplitter(splitter) + return setmetatableindex({},function(t,k) -- could be done in the sorter but seldom that many shared + local v = splitter(k,true) -- in other cases + t[k] = v + return v + end) end -]] - -local function byspec(dataset,list,method) -- todo: yearsuffix - local luadata = datasets[dataset].luadata - local details = datasets[dataset].details - local result = { } - local splitted = newsplitter(splitter) -- saves mem - -- local snippets = { } -- saves mem - local fields = settings_to_array(method) - for i=1,#fields do - local f = settings_to_array(fields[i]) - local r = { } - for i=1,#f do - local a, b = lpegmatch(splitspec,f[i]) - if b then - if a == "detail" or a == "entry" then - local t = currentspecification.types[b] - local w = t and writers[t] - if w then - r[#r+1] = formatters["(%s.%s and writers[%q](%s.%s))"](a,b,t,a,b) - else - r[#r+1] = formatters["%s.%s"](a,b,a,b) + + local template = [[ + local strip = sorters.strip + local writers = publications.writers + return function(entry,detail,splitted,i) -- snippets + return { + index = i, + split = { %s, splitted[tostring(i)] } + } + end + ]] + + local function byspec(dataset,list,method) -- todo: yearsuffix + local luadata = datasets[dataset].luadata + local details = datasets[dataset].details + local result = { } + local splitted = newsplitter(splitter) -- saves mem + -- local snippets = { } -- saves mem + local fields = settings_to_array(method) + for i=1,#fields do + local f = settings_to_array(fields[i]) + local r = { } + for i=1,#f do + local a, b = lpegmatch(splitspec,f[i]) + if b then + if a == "detail" or a == "entry" then + local t = currentspecification.types[b] + local w = t and writers[t] + if w then + r[#r+1] = formatters["(%s.%s and writers[%q](%s.%s))"](a,b,t,a,b) + else + r[#r+1] = formatters["%s.%s"](a,b,a,b) + end end + elseif a then + r[#r+1] = formatters["%s"](a) end - elseif a then - r[#r+1] = formatters["%s"](a) end - end - r[#r+1] = '""' - fields[i] = "splitted[strip(" .. concat(r," or ") .. ")]" - end - local action = formatters[template](concat(fields,", ")) - local prepare = loadstring(action) - if prepare then - prepare = prepare() - local dummy = { } - for i=1,#list do - -- either { tag, tag, ... } or { { tag, index }, { tag, index } } - local li = list[i] - local tag = type(li) == "string" and li or li[1] - local entry = luadata[tag] - local detail = details[tag] - if entry and detail then - result[i] = prepare(entry,detail,splitted,i) -- ,snippets) - else - result[i] = prepare(dummy,dummy,splitted,i) -- ,snippets) + r[#r+1] = '""' + fields[i] = "splitted[strip(" .. concat(r," or ") .. ")]" + end + local action = formatters[template](concat(fields,", ")) + local prepare = loadstring(action) + if prepare then + prepare = prepare() + local dummy = { } + for i=1,#list do + -- either { tag, tag, ... } or { { tag, index }, { tag, index } } + local li = list[i] + local tag = type(li) == "string" and li or li[1] + local entry = luadata[tag] + local detail = details[tag] + if entry and detail then + result[i] = prepare(entry,detail,splitted,i) -- ,snippets) + else + result[i] = prepare(dummy,dummy,splitted,i) -- ,snippets) + end end end + return result end - return result -end -lists.sorters = { - [v_short] = function(dataset,rendering,list) - local shorts = rendering.shorts - local function compare(a,b) - local aa, bb = a and a[1], b and b[1] - if aa and bb then - aa, bb = shorts[aa], shorts[bb] - return aa and bb and aa < bb - end - return false - end - sort(list,compare) - end, - [v_reference] = function(dataset,rendering,list) - local function compare(a,b) - local aa, bb = a and a[1], b and b[1] - if aa and bb then - return aa and bb and aa < bb + lists.sorters = { + [v_short] = function(dataset,rendering,list) + local shorts = rendering.shorts + local function compare(a,b) + local aa, bb = a and a[1], b and b[1] + if aa and bb then + aa, bb = shorts[aa], shorts[bb] + return aa and bb and aa < bb + end + return false end - return false - end - sort(list,compare) - end, - [v_dataset] = function(dataset,rendering,list) - local function compare(a,b) - local aa, bb = a and a[1], b and b[1] - if aa and bb then - aa, bb = list[aa].index or 0, list[bb].index or 0 - return aa and bb and aa < bb + sort(list,compare) + end, + [v_reference] = function(dataset,rendering,list) + local function compare(a,b) + local aa, bb = a and a[1], b and b[1] + if aa and bb then + return aa and bb and aa < bb + end + return false end - return false - end - sort(list,compare) - end, - [v_default] = function(dataset,rendering,list,sorttype) -- experimental - if sorttype == "" or sorttype == v_default then + sort(list,compare) + end, + [v_dataset] = function(dataset,rendering,list) local function compare(a,b) - local aa, bb = a and a[3], b and b[3] + local aa, bb = a and a[1], b and b[1] if aa and bb then + aa, bb = list[aa].index or 0, list[bb].index or 0 return aa and bb and aa < bb end return false end sort(list,compare) - else - local valid = byspec(dataset,list,sorttype) + end, + [v_default] = function(dataset,rendering,list,sorttype) -- experimental + if sorttype == "" or sorttype == v_default then + local function compare(a,b) + local aa, bb = a and a[3], b and b[3] + if aa and bb then + return aa and bb and aa < bb + end + return false + end + sort(list,compare) + else + local valid = byspec(dataset,list,sorttype) + if #valid == 0 or #valid ~= #list then + -- nothing to sort + else + -- if needed we can wrap compare and use the list directly but this is cleaner + sorters.sort(valid,sortcomparer) + for i=1,#valid do + local v = valid[i] + valid[i] = list[v.index] + end + return valid + end + end + end, + [v_author] = function(dataset,rendering,list) + local valid = publications.authors.sorters.author(dataset,list) if #valid == 0 or #valid ~= #list then -- nothing to sort else @@ -1554,1181 +1549,1176 @@ lists.sorters = { end return valid end - end - end, - [v_author] = function(dataset,rendering,list) - local valid = publications.authors.sorters.author(dataset,list) - if #valid == 0 or #valid ~= #list then - -- nothing to sort - else - -- if needed we can wrap compare and use the list directly but this is cleaner - sorters.sort(valid,sortcomparer) - for i=1,#valid do - local v = valid[i] - valid[i] = list[v.index] - end - return valid - end - end, -} + end, + } --- for determining width - -local lastreferencenumber = 0 -- document wide - -function lists.prepareentries(dataset) - local rendering = renderings[dataset] - local list = rendering.list - local used = rendering.used - local forceall = rendering.criterium == v_all - local repeated = rendering.repeated == v_yes - local sorttype = rendering.sorttype or v_default - local sorter = lists.sorters[sorttype] or lists.sorters[v_default] - local current = datasets[dataset] - local luadata = current.luadata - local details = current.details - local newlist = { } - for i=1,#list do - local li = list[i] - local tag = li[1] - local entry = luadata[tag] - if entry then - if forceall or repeated or not used[tag] then - newlist[#newlist+1] = li - -- already here: - if not repeated then - used[tag] = true -- beware we keep the old state (one can always use criterium=all) - end - local detail = details[tag] - if detail then - local referencenumber = detail.referencenumber - if not referencenumber then - lastreferencenumber = lastreferencenumber + 1 - referencenumber = lastreferencenumber - detail.referencenumber = lastreferencenumber + -- for determining width + + local lastreferencenumber = 0 -- document wide + + function lists.prepareentries(dataset) + local rendering = renderings[dataset] + local list = rendering.list + local used = rendering.used + local forceall = rendering.criterium == v_all + local repeated = rendering.repeated == v_yes + local sorttype = rendering.sorttype or v_default + local sorter = lists.sorters[sorttype] or lists.sorters[v_default] + local current = datasets[dataset] + local luadata = current.luadata + local details = current.details + local newlist = { } + for i=1,#list do + local li = list[i] + local tag = li[1] + local entry = luadata[tag] + if entry then + if forceall or repeated or not used[tag] then + newlist[#newlist+1] = li + -- already here: + if not repeated then + used[tag] = true -- beware we keep the old state (one can always use criterium=all) + end + local detail = details[tag] + if detail then + local referencenumber = detail.referencenumber + if not referencenumber then + lastreferencenumber = lastreferencenumber + 1 + referencenumber = lastreferencenumber + detail.referencenumber = lastreferencenumber + end + li[3] = referencenumber + else + report("missing details for tag %a in dataset %a (enhanced: %s)",tag,dataset,current.enhanced and "yes" or "no") + -- weird, this shouldn't happen .. all have a detail + lastreferencenumber = lastreferencenumber + 1 + details[tag] = { referencenumber = lastreferencenumber } + li[3] = lastreferencenumber end - li[3] = referencenumber - else - report("missing details for tag %a in dataset %a (enhanced: %s)",tag,dataset,current.enhanced and "yes" or "no") - -- weird, this shouldn't happen .. all have a detail - lastreferencenumber = lastreferencenumber + 1 - details[tag] = { referencenumber = lastreferencenumber } - li[3] = lastreferencenumber end end end + rendering.list = type(sorter) == "function" and sorter(dataset,rendering,newlist,sorttype) or newlist end - rendering.list = type(sorter) == "function" and sorter(dataset,rendering,newlist,sorttype) or newlist -end -function lists.fetchentries(dataset) - local rendering = renderings[dataset] - local list = rendering.list - for i=1,#list do - local li = list[i] - ctx_btxsettag(li[1]) - ctx_btxsetnumber(li[3]) - ctx_btxchecklistentry() + function lists.fetchentries(dataset) + local rendering = renderings[dataset] + local list = rendering.list + for i=1,#list do + local li = list[i] + ctx_btxsettag(li[1]) + ctx_btxsetnumber(li[3]) + ctx_btxchecklistentry() + end end -end --- for rendering - --- setspecification - -function commands.btxflushpages(dataset,tag) - -- todo: interaction - local rendering = renderings[dataset] - local pages = rendering.pages[tag] - if not pages then - return - end - local nofpages = #pages - if nofpages == 0 then - return - end - local first_p = nil - local first_r = nil - local last_p = nil - local last_r = nil - local ranges = { } - local nofdone = 0 - local function flush() - if last_r and first_r ~= last_r then - ranges[#ranges+1] = { first_p, last_p } - else - ranges[#ranges+1] = { first_p } - end - end - for i=1,nofpages do - local next_p = pages[i] - local next_r = next_p[2].realpage - if not first_r then - first_p = next_p - first_r = next_r - elseif last_r + 1 == next_r then - -- continue - elseif first_r then - flush() - first_p = next_p - first_r = next_r + -- for rendering + + -- setspecification + + function commands.btxflushpages(dataset,tag) + -- todo: interaction + local rendering = renderings[dataset] + local pages = rendering.pages[tag] + if not pages then + return end - last_p = next_p - last_r = next_r - end - if first_r then - flush() - end - local nofranges = #ranges - for i=1,nofranges do - local r = ranges[i] - ctx_btxsetconcat(concatstate(i,nofranges)) - local first, last = r[1], r[2] - ctx_btxsetfirstinternal(first[2].internal) - ctx_btxsetfirstpage(first[1]) - if last then - ctx_btxsetlastinternal(last[2].internal) - ctx_btxsetlastpage(last[1]) + local nofpages = #pages + if nofpages == 0 then + return end - ctx_btxpagesetup() - end -end - -function lists.flushentries(dataset,textmode) - local rendering = renderings[dataset] - local list = rendering.list - local luadata = datasets[dataset].luadata - -- maybe a startflushing here - ignoredfields = rendering.ignored or { } - -- - for i=1,#list do - local li = list[i] - local tag = li[1] - local n = li[3] - local entry = luadata[tag] - local combined = entry.combined - local language = entry.language - if combined then - ctx_btxsetcombis(concat(combined,",")) - end - ctx_btxsetcategory(entry.category or "unknown") - ctx_btxsettag(tag) - ctx_btxsetnumber(n) - if language then - ctx_btxsetlanguage(language) - end - local bl = li[5] - if bl and bl ~= "" then - ctx_btxsetbacklink(bl) - ctx_btxsetbacktrace(concat(li," ",5)) - local uc = citetolist[tonumber(bl)] - if uc then - ctx_btxsetinternal(uc.references.internal or "") + local first_p = nil + local first_r = nil + local last_p = nil + local last_r = nil + local ranges = { } + local nofdone = 0 + local function flush() + if last_r and first_r ~= last_r then + ranges[#ranges+1] = { first_p, last_p } + else + ranges[#ranges+1] = { first_p } end - else - -- nothing end - local userdata = li[4] - if userdata then - local b = userdata.btxbtx - local a = userdata.btxatx - if b then - ctx_btxsetbefore(b) - end - if a then - ctx_btxsetafter(a) + for i=1,nofpages do + local next_p = pages[i] + local next_r = next_p[2].realpage + if not first_r then + first_p = next_p + first_r = next_r + elseif last_r + 1 == next_r then + -- continue + elseif first_r then + flush() + first_p = next_p + first_r = next_r end + last_p = next_p + last_r = next_r end - rendering.userdata = userdata - if textmode then - ctx_btxhandlelisttextentry() - else - ctx_btxhandlelistentry() + if first_r then + flush() + end + local nofranges = #ranges + for i=1,nofranges do + local r = ranges[i] + ctx_btxsetconcat(concatstate(i,nofranges)) + local first, last = r[1], r[2] + ctx_btxsetfirstinternal(first[2].internal) + ctx_btxsetfirstpage(first[1]) + if last then + ctx_btxsetlastinternal(last[2].internal) + ctx_btxsetlastpage(last[1]) + end + ctx_btxpagesetup() end end - context(function() - -- wrapup - ignoredfields = nil - setspecification(false) - end) -end -local function getuserdata(dataset,key) - local rendering = renderings[dataset] - if rendering then - local userdata = rendering.userdata - if userdata then - local value = userdata[key] - if value and value ~= "" then - return value + function lists.flushentries(dataset,textmode) + local rendering = renderings[dataset] + local list = rendering.list + local luadata = datasets[dataset].luadata + -- maybe a startflushing here + ignoredfields = rendering.ignored or { } + -- + for i=1,#list do + local li = list[i] + local tag = li[1] + local n = li[3] + local entry = luadata[tag] + local combined = entry.combined + local language = entry.language + if combined then + ctx_btxsetcombis(concat(combined,",")) + end + ctx_btxsetcategory(entry.category or "unknown") + ctx_btxsettag(tag) + ctx_btxsetnumber(n) + if language then + ctx_btxsetlanguage(language) + end + local bl = li[5] + if bl and bl ~= "" then + ctx_btxsetbacklink(bl) + ctx_btxsetbacktrace(concat(li," ",5)) + local uc = citetolist[tonumber(bl)] + if uc then + ctx_btxsetinternal(uc.references.internal or "") + end + else + -- nothing + end + local userdata = li[4] + if userdata then + local b = userdata.btxbtx + local a = userdata.btxatx + if b then + ctx_btxsetbefore(b) + end + if a then + ctx_btxsetafter(a) + end + end + rendering.userdata = userdata + if textmode then + ctx_btxhandlelisttextentry() + else + ctx_btxhandlelistentry() + end + end + context(function() + -- wrapup + ignoredfields = nil + setspecification(false) + end) + end + + local function getuserdata(dataset,key) + local rendering = renderings[dataset] + if rendering then + local userdata = rendering.userdata + if userdata then + local value = userdata[key] + if value and value ~= "" then + return value + end end end end -end -lists.uservariable = getuserdata + lists.uservariable = getuserdata -function commands.btxuservariable(dataset,key) - local value = getuserdata(dataset,key) - if value then - context(value) + function commands.btxuservariable(dataset,key) + local value = getuserdata(dataset,key) + if value then + context(value) + end end -end -function commands.btxdoifelseuservariable(dataset,key) - if getuserdata(dataset,key) then - ctx_firstoftwoarguments() - else - ctx_secondoftwoarguments() + function commands.btxdoifelseuservariable(dataset,key) + if getuserdata(dataset,key) then + ctx_firstoftwoarguments() + else + ctx_secondoftwoarguments() + end end -end -function lists.filterall(dataset) - local r = renderings[dataset] - local list = r.list - local registered = r.registered - for i=1,#registered do - list[i] = { registered[i], i, 0, false, false } + function lists.filterall(dataset) + local r = renderings[dataset] + local list = r.list + local registered = r.registered + for i=1,#registered do + list[i] = { registered[i], i, 0, false, false } + end end -end - -commands.btxresolvelistreference = lists.resolve -commands.btxaddtolist = lists.addentry -commands.btxcollectlistentries = lists.collectentries -commands.btxpreparelistentries = lists.prepareentries -commands.btxfetchlistentries = lists.fetchentries -commands.btxflushlistentries = lists.flushentries -commands.btxflushlistentry = lists.flushentry -local citevariants = { } -publications.citevariants = citevariants + commands.btxresolvelistreference = lists.resolve + commands.btxaddtolist = lists.addentry + commands.btxcollectlistentries = lists.collectentries + commands.btxpreparelistentries = lists.prepareentries + commands.btxfetchlistentries = lists.fetchentries + commands.btxflushlistentries = lists.flushentries + commands.btxflushlistentry = lists.flushentry -function commands.btxhandlecite(specification) - local dataset = specification.dataset or "" -- standard - local reference = specification.reference - local variant = specification.variant or defaultvariant - if not reference or reference == "" then - return - end - -- - specification.variant = variant - specification.compress = specification.compress == v_yes - specification.markentry = specification.markentry ~= false - -- - local prefix, rest = lpegmatch(prefixsplitter,reference) - if prefix and rest then - specification.dataset = prefix - specification.reference = rest - end - -- - -- - if trace_cite then - report_cite("inject, dataset: %s, tag: %s, variant: %s, compressed", - specification.dataset or "-", - specification.reference, - specification.variant - ) - end - -- - ctx_setvalue("currentbtxdataset",dataset) - -- - citevariants[variant](specification) -- we always fall back on default end +do -function commands.btxhandlenocite(specification) - local dataset = specification.dataset or "" -- standard - local reference = specification.reference - if not reference or reference == "" then - return - end - -- - local markentry = specification.markentry ~= false - local internal = specification.internal or "" - -- - local prefix, rest = lpegmatch(prefixsplitter,reference) - if rest then - dataset = prefix - reference = rest - end - -- - if trace_cite then - report_cite("mark, dataset: %s, tags: %s",dataset or "-",reference) - end - -- - local reference = publications.parenttag(dataset,reference) - -- - local found, todo, list = findallused(dataset,reference,internal) - -- - tobemarked = markentry and todo - if found and tobemarked then - flushmarked(dataset,list) - commands.flushmarked() -- here (could also be done in caller) - end -end - --- function commands.btxcitevariant(dataset,block,tags,variant) -- uses? specification ? --- local action = citevariants[variant] --- if action then --- action(dataset,tags,variant) --- end --- end - --- sorter - -local keysorter = function(a,b) return a.sortkey < b.sortkey end - --- local suffix = 0 --- local function setsuffix(entry,suffix,sortfld) --- entry.suffix = suffix --- local dataset = datasets[entry.dataset] --- if dataset then --- local suffixes = dataset.suffixes[entry.tag] --- if suffixes then --- suffixes[sortfld] = suffix --- else --- dataset.suffixes[entry.tag] = { [sortfld] = suffix } --- end --- end --- end --- for i=1,#source do --- local entry = source[i] --- local sortfld = entry.sortfld --- if sortfld then --- local value = entry.sortkey --- if value == oldvalue then --- if suffix == 0 then --- suffix = 1 --- local entry = source[i-1] --- setsuffix(entry,suffix,sortfld) --- end --- suffix = suffix + 1 --- setsuffix(entry,suffix,sortfld) --- else --- oldvalue = value --- suffix = 0 --- end --- else --- break --- end --- end - -local function compresslist(source) - for i=1,#source do - if type(source[i].sortkey) ~= "number" then - return source - end - end - local first, last, firstr, lastr - local target, noftarget, tags = { }, 0, { } - sort(source,keysorter) - local oldvalue = nil - local function flushrange() - noftarget = noftarget + 1 - if last > first + 1 then - target[noftarget] = { - first = firstr, - last = lastr, - tags = tags, - } - else - target[noftarget] = firstr - if last > first then - noftarget = noftarget + 1 - target[noftarget] = lastr + local citevariants = { } + publications.citevariants = citevariants + + function commands.btxhandlecite(specification) + local dataset = specification.dataset or "" -- standard + local reference = specification.reference + local variant = specification.variant or defaultvariant + if not reference or reference == "" then + return + end + -- + specification.variant = variant + specification.compress = specification.compress == v_yes + specification.markentry = specification.markentry ~= false + -- + local prefix, rest = lpegmatch(prefixsplitter,reference) + if prefix and rest then + specification.dataset = prefix + specification.reference = rest + end + -- + -- + if trace_cite then + report_cite("inject, dataset: %s, tag: %s, variant: %s, compressed", + specification.dataset or "-", + specification.reference, + specification.variant + ) + end + -- + ctx_setvalue("currentbtxdataset",dataset) + -- + citevariants[variant](specification) -- we always fall back on default + end + + + function commands.btxhandlenocite(specification) + local dataset = specification.dataset or "" -- standard + local reference = specification.reference + if not reference or reference == "" then + return + end + -- + local markentry = specification.markentry ~= false + local internal = specification.internal or "" + -- + local prefix, rest = lpegmatch(prefixsplitter,reference) + if rest then + dataset = prefix + reference = rest + end + -- + if trace_cite then + report_cite("mark, dataset: %s, tags: %s",dataset or "-",reference) + end + -- + local reference = publications.parenttag(dataset,reference) + -- + local found, todo, list = findallused(dataset,reference,internal) + -- + tobemarked = markentry and todo + if found and tobemarked then + flushmarked(dataset,list) + commands.flushmarked() -- here (could also be done in caller) + end + end + + -- function commands.btxcitevariant(dataset,block,tags,variant) -- uses? specification ? + -- local action = citevariants[variant] + -- if action then + -- action(dataset,tags,variant) + -- end + -- end + + -- sorter + + local keysorter = function(a,b) return a.sortkey < b.sortkey end + + -- local suffix = 0 + -- local function setsuffix(entry,suffix,sortfld) + -- entry.suffix = suffix + -- local dataset = datasets[entry.dataset] + -- if dataset then + -- local suffixes = dataset.suffixes[entry.tag] + -- if suffixes then + -- suffixes[sortfld] = suffix + -- else + -- dataset.suffixes[entry.tag] = { [sortfld] = suffix } + -- end + -- end + -- end + -- for i=1,#source do + -- local entry = source[i] + -- local sortfld = entry.sortfld + -- if sortfld then + -- local value = entry.sortkey + -- if value == oldvalue then + -- if suffix == 0 then + -- suffix = 1 + -- local entry = source[i-1] + -- setsuffix(entry,suffix,sortfld) + -- end + -- suffix = suffix + 1 + -- setsuffix(entry,suffix,sortfld) + -- else + -- oldvalue = value + -- suffix = 0 + -- end + -- else + -- break + -- end + -- end + + local function compresslist(source) + for i=1,#source do + if type(source[i].sortkey) ~= "number" then + return source end end - tags = { } - end - for i=1,#source do - local entry = source[i] - local current = entry.sortkey - if not first then - first, last, firstr, lastr = current, current, entry, entry - elseif current == last + 1 then - last, lastr = current, entry - else + local first, last, firstr, lastr + local target, noftarget, tags = { }, 0, { } + sort(source,keysorter) + local oldvalue = nil + local function flushrange() + noftarget = noftarget + 1 + if last > first + 1 then + target[noftarget] = { + first = firstr, + last = lastr, + tags = tags, + } + else + target[noftarget] = firstr + if last > first then + noftarget = noftarget + 1 + target[noftarget] = lastr + end + end + tags = { } + end + for i=1,#source do + local entry = source[i] + local current = entry.sortkey + if not first then + first, last, firstr, lastr = current, current, entry, entry + elseif current == last + 1 then + last, lastr = current, entry + else + flushrange() + first, last, firstr, lastr = current, current, entry, entry + end + tags[#tags+1] = entry.tag + end + if first and last then flushrange() - first, last, firstr, lastr = current, current, entry, entry end - tags[#tags+1] = entry.tag + return target end - if first and last then - flushrange() - end - return target -end --- local source = { --- { tag = "one", internal = 1, value = "foo", page = 1 }, --- { tag = "two", internal = 2, value = "bar", page = 2 }, --- { tag = "three", internal = 3, value = "gnu", page = 3 }, --- } --- --- local target = compresslist(source) - -local numberonly = R("09")^1 / tonumber + P(1)^0 -local f_missing = formatters["<%s>"] + -- local source = { + -- { tag = "one", internal = 1, value = "foo", page = 1 }, + -- { tag = "two", internal = 2, value = "bar", page = 2 }, + -- { tag = "three", internal = 3, value = "gnu", page = 3 }, + -- } + -- + -- local target = compresslist(source) --- maybe also sparse (e.g. pages) + local numberonly = R("09")^1 / tonumber + P(1)^0 + local f_missing = formatters["<%s>"] --- a bit redundant access to datasets + -- maybe also sparse (e.g. pages) -local function processcite(presets,specification) - -- - if specification then - setmetatableindex(specification,presets) - else - specification = presets - end - -- - local dataset = specification.dataset - local reference = specification.reference - local internal = specification.internal - local setup = specification.variant - local compress = specification.compress - local getter = specification.getter - local setter = specification.setter - local compressor = specification.compressor - -- + -- a bit redundant access to datasets - local reference = publications.parenttag(dataset,reference) - -- - local found, todo, list = findallused(dataset,reference,internal) - tobemarked = specification.markentry and todo - -- - if found and setup then - local source = { } - local badkey = false - local luadata = datasets[dataset].luadata - for i=1,#found do - local entry = found[i] - local tag = entry.userdata.btxref - -- we can probably move the test into the flush - -- local category = luadata[tag].category - -- if currentspecificationfields[category][setup] then - local internal = entry.references.internal - local data = setter(dataset,tag,entry,internal) - if compress and not compressor then - local sortkey = data.sortkey - if sortkey then - local key = lpegmatch(numberonly,sortkey) - if key then - data.sortkey = key + local function processcite(presets,specification) + -- + if specification then + setmetatableindex(specification,presets) + else + specification = presets + end + -- + local dataset = specification.dataset + local reference = specification.reference + local internal = specification.internal + local setup = specification.variant + local compress = specification.compress + local getter = specification.getter + local setter = specification.setter + local compressor = specification.compressor + -- + + local reference = publications.parenttag(dataset,reference) + -- + local found, todo, list = findallused(dataset,reference,internal) + tobemarked = specification.markentry and todo + -- + if found and setup then + local source = { } + local badkey = false + local luadata = datasets[dataset].luadata + for i=1,#found do + local entry = found[i] + local tag = entry.userdata.btxref + -- we can probably move the test into the flush + -- local category = luadata[tag].category + -- if currentspecificationfields[category][setup] then + local internal = entry.references.internal + local data = setter(dataset,tag,entry,internal) + if compress and not compressor then + local sortkey = data.sortkey + if sortkey then + local key = lpegmatch(numberonly,sortkey) + if key then + data.sortkey = key + else + badkey = true + end else badkey = true end + end + if type(data) == "table" then + source[#source+1] = data else - badkey = true + report("error in cite rendering %a",setup or "?") end - end - if type(data) == "table" then - source[#source+1] = data - else - report("error in cite rendering %a",setup or "?") - end - -- else - -- report("cite rendering %a is not available for %a",setup,category) - -- end - end + -- else + -- report("cite rendering %a is not available for %a",setup,category) + -- end + end - local lefttext = specification.lefttext - local righttext = specification.righttext - local before = specification.before - local after = specification.after + local lefttext = specification.lefttext + local righttext = specification.righttext + local before = specification.before + local after = specification.after - if lefttext and lefttext ~= "" then lefttext = settings_to_array(lefttext) end - if righttext and righttext ~= "" then righttext = settings_to_array(righttext) end - if before and before ~= "" then before = settings_to_array(before) end - if after and after ~= "" then after = settings_to_array(after) end + if lefttext and lefttext ~= "" then lefttext = settings_to_array(lefttext) end + if righttext and righttext ~= "" then righttext = settings_to_array(righttext) end + if before and before ~= "" then before = settings_to_array(before) end + if after and after ~= "" then after = settings_to_array(after) end - local function flush(i,n,entry,last) - local tag = entry.tag - local currentcitation = markcite(dataset,tag) - -- - ctx_btxstartcite() - ctx_btxsettag(tag) - -- - if lefttext then ctx_btxsetlefttext (lefttext [i] or #lefttext == 1 and lefttext [1] or "") end - if righttext then ctx_btxsetrighttext(righttext[i] or #righttext == 1 and righttext[1] or "") end - if before then ctx_btxsetbefore (before [i] or #before == 1 and before [1] or "") end - if after then ctx_btxsetafter (after [i] or #after == 1 and after [1] or "") end - -- - ctx_btxsetbacklink(currentcitation) - local bl = listtocite[currentcitation] - if bl then - -- we refer to a coming list entry - ctx_btxsetinternal(bl.references.internal or "") - else - -- we refer to a previous list entry - ctx_btxsetinternal(entry.internal or "") - end - local language = entry.language - if language then - ctx_btxsetlanguage(language) - end - if not getter(entry,last) then - ctx_btxsetfirst(f_missing(tag)) + local function flush(i,n,entry,last) + local tag = entry.tag + local currentcitation = markcite(dataset,tag) + -- + ctx_btxstartcite() + ctx_btxsettag(tag) + -- + if lefttext then ctx_btxsetlefttext (lefttext [i] or #lefttext == 1 and lefttext [1] or "") end + if righttext then ctx_btxsetrighttext(righttext[i] or #righttext == 1 and righttext[1] or "") end + if before then ctx_btxsetbefore (before [i] or #before == 1 and before [1] or "") end + if after then ctx_btxsetafter (after [i] or #after == 1 and after [1] or "") end + -- + ctx_btxsetbacklink(currentcitation) + local bl = listtocite[currentcitation] + if bl then + -- we refer to a coming list entry + ctx_btxsetinternal(bl.references.internal or "") + else + -- we refer to a previous list entry + ctx_btxsetinternal(entry.internal or "") + end + local language = entry.language + if language then + ctx_btxsetlanguage(language) + end + if not getter(entry,last) then + ctx_btxsetfirst(f_missing(tag)) + end + ctx_btxsetconcat(concatstate(i,n)) + ctx_btxcitesetup(setup) + ctx_btxstopcite() end - ctx_btxsetconcat(concatstate(i,n)) - ctx_btxcitesetup(setup) - ctx_btxstopcite() - end - if compress and not badkey then - local target = (compressor or compresslist)(source) - local nofcollected = #target - if nofcollected == 0 then - unknowncite(reference) - else - for i=1,nofcollected do - local entry = target[i] - local first = entry.first - if first then - flush(i,nofcollected,first,entry.last) - else - flush(i,nofcollected,entry) + if compress and not badkey then + local target = (compressor or compresslist)(source) + local nofcollected = #target + if nofcollected == 0 then + unknowncite(reference) + else + for i=1,nofcollected do + local entry = target[i] + local first = entry.first + if first then + flush(i,nofcollected,first,entry.last) + else + flush(i,nofcollected,entry) + end end end - end - else - local nofcollected = #source - if nofcollected == 0 then - unknowncite(reference) else - for i=1,nofcollected do - flush(i,nofcollected,source[i]) + local nofcollected = #source + if nofcollected == 0 then + unknowncite(reference) + else + for i=1,nofcollected do + flush(i,nofcollected,source[i]) + end end end end + if tobemarked then + flushmarked(dataset,list) + commands.flushmarked() -- here (could also be done in caller) + end end - if tobemarked then - flushmarked(dataset,list) - commands.flushmarked() -- here (could also be done in caller) - end -end -local function simplegetter(first,last,field) - local value = first[field] - if value then - ctx_btxsetfirst(value) - if last then - ctx_btxsetsecond(last[field]) + local function simplegetter(first,last,field) + local value = first[field] + if value then + ctx_btxsetfirst(value) + if last then + ctx_btxsetsecond(last[field]) + end + return true end - return true end -end -local setters = setmetatableindex({},function(t,k) - local v = function(dataset,tag,entry,internal) - local value = getfield(dataset,tag,k) - return { - tag = tag, - internal = internal, - [k] = value, - sortkey = value, - sortfld = k, - } - end - t[k] = v - return v -end) + local setters = setmetatableindex({},function(t,k) + local v = function(dataset,tag,entry,internal) + local value = getfield(dataset,tag,k) + return { + tag = tag, + internal = internal, + [k] = value, + sortkey = value, + sortfld = k, + } + end + t[k] = v + return v + end) -local getters = setmetatableindex({},function(t,k) - local v = function(first,last) - return simplegetter(first,last,k) - end - t[k] = v - return v -end) + local getters = setmetatableindex({},function(t,k) + local v = function(first,last) + return simplegetter(first,last,k) + end + t[k] = v + return v + end) --- todo: just a sort key and then fetch normal by fieldname + -- todo: just a sort key and then fetch normal by fieldname --- setmetatableindex(citevariants,function(t,k) --- local p = registeredcitevariants[k] --- local v = p and p ~= k and rawget(t,p) or defaultvariant --- t[k] = v --- return v --- end) + -- setmetatableindex(citevariants,function(t,k) + -- local p = registeredcitevariants[k] + -- local v = p and p ~= k and rawget(t,p) or defaultvariant + -- t[k] = v + -- return v + -- end) -setmetatableindex(citevariants,function(t,k) - local p = registeredcitevariants[k] - local v = nil - if p and p ~= "" then - v = rawget(t,p) - end - if not v then - p = defaultvariant or "default" - v = rawget(t,p) + setmetatableindex(citevariants,function(t,k) + local p = registeredcitevariants[k] + local v = nil + if p and p ~= "" then + v = rawget(t,p) + end + if not v then + p = defaultvariant or "default" + v = rawget(t,p) + end + report_cite("variant %a falls back on %a",k,p) + t[k] = v + return v + end) + + function citevariants.default(presets) -- no longer used + local variant = presets.variant + processcite(presets,{ + setter = setters[variant], + getter = getters[variant], + }) end - report_cite("variant %a falls back on %a",k,p) - t[k] = v - return v -end) -function citevariants.default(presets) -- no longer used - local variant = presets.variant - processcite(presets,{ - setter = setters[variant], - getter = getters[variant], - }) -end + -- entry --- entry + do -do + local function setter(dataset,tag,entry,internal) + return { + tag = tag, + internal = internal, + } + end - local function setter(dataset,tag,entry,internal) - return { - tag = tag, - internal = internal, - } - end + local function getter(first,last) -- last not used + ctx_btxsetfirst(first.tag) + end - local function getter(first,last) -- last not used - ctx_btxsetfirst(first.tag) - end + function citevariants.entry(presets) + processcite(presets,{ + compress = false, + -- variant = presets.variant or "entry", + setter = setter, + getter = getter, + }) + end - function citevariants.entry(presets) - processcite(presets,{ - compress = false, - -- variant = presets.variant or "entry", - setter = setter, - getter = getter, - }) end -end - --- short + -- short -do + do - local function setter(dataset,tag,entry,internal) - return { - tag = tag, - internal = internal, - short = getdetail(dataset,tag,"short"), - suffix = getdetail(dataset,tag,"suffix"), - } - end + local function setter(dataset,tag,entry,internal) + return { + tag = tag, + internal = internal, + short = getdetail(dataset,tag,"short"), + suffix = getdetail(dataset,tag,"suffix"), + } + end - local function getter(first,last) -- last not used - local short = first.short - if short then - local suffix = first.suffix - if suffix then - ctx_btxsetfirst(short .. suffix) - else - ctx_btxsetfirst(short) + local function getter(first,last) -- last not used + local short = first.short + if short then + local suffix = first.suffix + if suffix then + ctx_btxsetfirst(short .. suffix) + else + ctx_btxsetfirst(short) + end + return true end - return true end - end - function citevariants.short(presets) - processcite(presets,{ - compress = false, - -- variant = presets.variant or "short", - setter = setter, - getter = getter, - }) - end + function citevariants.short(presets) + processcite(presets,{ + compress = false, + -- variant = presets.variant or "short", + setter = setter, + getter = getter, + }) + end -end + end --- pages (no compress) + -- pages (no compress) -do + do - local function setter(dataset,tag,entry,internal) - return { - dataset = dataset, - tag = tag, - internal = internal, - pages = getdetail(dataset,tag,"pages"), - } - end + local function setter(dataset,tag,entry,internal) + return { + dataset = dataset, + tag = tag, + internal = internal, + pages = getdetail(dataset,tag,"pages"), + } + end - local function getter(first,last) - local pages = first.pages - if pages then - if type(pages) == "table" then - ctx_btxsetfirst(pages[1]) - ctx_btxsetsecond(pages[2]) - else - ctx_btxsetfirst(pages) + local function getter(first,last) + local pages = first.pages + if pages then + if type(pages) == "table" then + ctx_btxsetfirst(pages[1]) + ctx_btxsetsecond(pages[2]) + else + ctx_btxsetfirst(pages) + end + return true end - return true end - end - function citevariants.page(presets) - processcite(presets,{ - -- variant = presets.variant or "page", - setter = setter, - getter = getter, - }) + function citevariants.page(presets) + processcite(presets,{ + -- variant = presets.variant or "page", + setter = setter, + getter = getter, + }) + end + end -end + -- num --- num + do -do + local function setter(dataset,tag,entry,internal) + local entries = entry.entries + local text = entries and entries.text or "?" + return { + tag = tag, + internal = internal, + num = text, + sortkey = text, + } + end - local function setter(dataset,tag,entry,internal) - local entries = entry.entries - local text = entries and entries.text or "?" - return { - tag = tag, - internal = internal, - num = text, - sortkey = text, - } - end + local function getter(first,last) + return simplegetter(first,last,"num") + end - local function getter(first,last) - return simplegetter(first,last,"num") - end + function citevariants.num(presets) + processcite(presets,{ + -- variant = presets.variant or "num", + setter = setter, + getter = getter, + }) + end - function citevariants.num(presets) - processcite(presets,{ - -- variant = presets.variant or "num", - setter = setter, - getter = getter, - }) end -end + -- year --- year + do -do + local function setter(dataset,tag,entry,internal) + return { + dataset = dataset, + tag = tag, + internal = internal, + year = getfield(dataset,tag,"year"), + suffix = getdetail(dataset,tag,"suffix"), + sortkey = getdetail(dataset,tag,"suffixedyear"), + } + end - local function setter(dataset,tag,entry,internal) - return { - dataset = dataset, - tag = tag, - internal = internal, - year = getfield(dataset,tag,"year"), - suffix = getdetail(dataset,tag,"suffix"), - sortkey = getdetail(dataset,tag,"suffixedyear"), - } - end + local function getter(first,last) + return simplegetter(first,last,"year") + end - local function getter(first,last) - return simplegetter(first,last,"year") - end + function citevariants.year(presets) + processcite(presets,{ + -- variant = presets.variant or "year", + setter = setter, + getter = getter, + }) + end - function citevariants.year(presets) - processcite(presets,{ - -- variant = presets.variant or "year", - setter = setter, - getter = getter, - }) end -end + -- index | serial --- index | serial + do -do + local function setter(dataset,tag,entry,internal) + local index = getfield(dataset,tag,"index") + return { + dataset = dataset, + tag = tag, + internal = internal, + index = index, + sortkey = index, + } + end - local function setter(dataset,tag,entry,internal) - local index = getfield(dataset,tag,"index") - return { - dataset = dataset, - tag = tag, - internal = internal, - index = index, - sortkey = index, - } - end + local function getter(first,last) + return simplegetter(first,last,"index") + end - local function getter(first,last) - return simplegetter(first,last,"index") - end + function citevariants.index(presets) + processcite(presets,{ + -- variant = presets.variant or "index", + setter = setter, + getter = getter, + }) + end - function citevariants.index(presets) - processcite(presets,{ - -- variant = presets.variant or "index", - setter = setter, - getter = getter, - }) - end + function citevariants.serial(presets) + processcite(presets,{ + -- variant = presets.variant or "serial", + setter = setter, + getter = getter, + }) + end - function citevariants.serial(presets) - processcite(presets,{ - -- variant = presets.variant or "serial", - setter = setter, - getter = getter, - }) end -end + -- category | type --- category | type + do -do + local function setter(dataset,tag,entry,internal) + return { + dataset = dataset, + tag = tag, + internal = internal, + category = getfield(dataset,tag,"category"), + } + end - local function setter(dataset,tag,entry,internal) - return { - dataset = dataset, - tag = tag, - internal = internal, - category = getfield(dataset,tag,"category"), - } - end + local function getter(first,last) + return simplegetter(first,last,"category") + end - local function getter(first,last) - return simplegetter(first,last,"category") - end + function citevariants.category(presets) + processcite(presets,{ + -- variant = presets.variant or "serial", + setter = setter, + getter = getter, + }) + end - function citevariants.category(presets) - processcite(presets,{ - -- variant = presets.variant or "serial", - setter = setter, - getter = getter, - }) - end + function citevariants.type(presets) + processcite(presets,{ + -- variant = presets.variant or "type", + setter = setter, + getter = getter, + }) + end - function citevariants.type(presets) - processcite(presets,{ - -- variant = presets.variant or "type", - setter = setter, - getter = getter, - }) end -end + -- key | tag --- key | tag + do -do + local function setter(dataset,tag,entry,internal) + return { + dataset = dataset, + tag = tag, + internal = internal, + } + end - local function setter(dataset,tag,entry,internal) - return { - dataset = dataset, - tag = tag, - internal = internal, - } - end + local function getter(first,last) + ctx_btxsetfirst(first.tag) + return true + end - local function getter(first,last) - ctx_btxsetfirst(first.tag) - return true - end + function citevariants.key(presets) + return processcite(presets,{ + variant = "key", + setter = setter, + getter = getter, + }) + end - function citevariants.key(presets) - return processcite(presets,{ - variant = "key", - setter = setter, - getter = getter, - }) - end + function citevariants.tag(presets) + return processcite(presets,{ + variant = "tag", + setter = setter, + getter = getter, + }) + end - function citevariants.tag(presets) - return processcite(presets,{ - variant = "tag", - setter = setter, - getter = getter, - }) end -end + -- todo : sort + -- todo : choose between publications or commands namespace + -- todo : use details.author + -- todo : sort details.author + -- (name, name and name) .. how names? how sorted? + -- todo: we loop at the tex end .. why not here + -- \cite[{hh,afo},kvm] --- todo : sort --- todo : choose between publications or commands namespace --- todo : use details.author --- todo : sort details.author --- (name, name and name) .. how names? how sorted? --- todo: we loop at the tex end .. why not here --- \cite[{hh,afo},kvm] + -- common --- common + do -do + local getauthor = publications.authors.getauthor - local getauthor = publications.authors.getauthor - - local currentbtxciteauthor = function() - context.currentbtxciteauthor() - return true -- needed? - end + local currentbtxciteauthor = function() + context.currentbtxciteauthor() + return true -- needed? + end - local function authorcompressor(found) - local result = { } - local entries = { } - for i=1,#found do - local entry = found[i] - local author = entry.author - if author then - local aentries = entries[author] - if aentries then - aentries[#aentries+1] = entry - else - entries[author] = { entry } + local function authorcompressor(found) + local result = { } + local entries = { } + for i=1,#found do + local entry = found[i] + local author = entry.author + if author then + local aentries = entries[author] + if aentries then + aentries[#aentries+1] = entry + else + entries[author] = { entry } + end end end - end - for i=1,#found do - local entry = found[i] - local author = entry.author - if author then - local aentries = entries[author] - if not aentries then - result[#result+1] = entry - elseif aentries == true then - -- already done - else - result[#result+1] = entry - entry.entries = aentries - entries[author] = true + for i=1,#found do + local entry = found[i] + local author = entry.author + if author then + local aentries = entries[author] + if not aentries then + result[#result+1] = entry + elseif aentries == true then + -- already done + else + result[#result+1] = entry + entry.entries = aentries + entries[author] = true + end end end + -- todo: add letters (should we then tag all?) + return result end - -- todo: add letters (should we then tag all?) - return result - end - local function authorconcat(target,key,setup) - ctx_btxstartsubcite(setup) - local nofcollected = #target - if nofcollected == 0 then - unknowncite(tag) - else - for i=1,nofcollected do - local entry = target[i] - local first = entry.first - local tag = entry.tag - local currentcitation = markcite(entry.dataset,tag) - ctx_btxstartciteauthor() - ctx_btxsettag(tag) - ctx_btxsetbacklink(currentcitation) - local bl = listtocite[currentcitation] - ctx_btxsetinternal(bl and bl.references.internal or "") - if first then - ctx_btxsetfirst(first[key] or f_missing(first.tag)) - local suffix = entry.suffix - local value = entry.last[key] - if value then - ctx_btxsetsecond(value) - end - if suffix then - ctx_btxsetthird(suffix) - end - else - local suffix = entry.suffix - local value = entry[key] or f_missing(tag) - ctx_btxsetfirst(value) - if suffix then - ctx_btxsetthird(suffix) + local function authorconcat(target,key,setup) + ctx_btxstartsubcite(setup) + local nofcollected = #target + if nofcollected == 0 then + unknowncite(tag) + else + for i=1,nofcollected do + local entry = target[i] + local first = entry.first + local tag = entry.tag + local currentcitation = markcite(entry.dataset,tag) + ctx_btxstartciteauthor() + ctx_btxsettag(tag) + ctx_btxsetbacklink(currentcitation) + local bl = listtocite[currentcitation] + ctx_btxsetinternal(bl and bl.references.internal or "") + if first then + ctx_btxsetfirst(first[key] or f_missing(first.tag)) + local suffix = entry.suffix + local value = entry.last[key] + if value then + ctx_btxsetsecond(value) + end + if suffix then + ctx_btxsetthird(suffix) + end + else + local suffix = entry.suffix + local value = entry[key] or f_missing(tag) + ctx_btxsetfirst(value) + if suffix then + ctx_btxsetthird(suffix) + end end + ctx_btxsetconcat(concatstate(i,nofcollected)) + ctx_btxcitesetup(setup) + ctx_btxstopciteauthor() end - ctx_btxsetconcat(concatstate(i,nofcollected)) - ctx_btxcitesetup(setup) - ctx_btxstopciteauthor() - end - end - ctx_btxstopsubcite() - end - - local function authorsingle(entry,key,setup) - ctx_btxstartsubcite(setup) - ctx_btxstartciteauthor() - local tag = entry.tag - ctx_btxsettag(tag) - -- local currentcitation = markcite(entry.dataset,tag) - -- ctx_btxsetbacklink(currentcitation) - -- local bl = listtocite[currentcitation] - -- ctx_btxsetinternal(bl and bl.references.internal or "") - ctx_btxsetfirst(entry[key] or f_missing(tag)) - ctx_btxsetthird(entry.suffix) - ctx_btxcitesetup(setup) - ctx_btxstopciteauthor() - ctx_btxstopsubcite() - end - - local partialinteractive = false - - local function authorgetter(first,last,key,setup) -- only first - -- ctx_btxsetfirst(first.author) -- unformatted - ctx_btxsetfirst(currentbtxciteauthor) -- formatter (much slower) - local entries = first.entries - -- alternatively we can use a concat with one ... so that we can only make the - -- year interactive, as with the concat - if partialinteractive and not entries then - entries = { first } - end - if entries then - local c = compresslist(entries) - local f = function() authorconcat(c,key,setup) return true end -- indeed return true? - ctx_btxsetcount(#c) - ctx_btxsetsecond(f) - else - local f = function() authorsingle(first,key,setup) return true end -- indeed return true? - ctx_btxsetcount(0) - ctx_btxsetsecond(f) + end + ctx_btxstopsubcite() end - return true - end - -- author + local function authorsingle(entry,key,setup) + ctx_btxstartsubcite(setup) + ctx_btxstartciteauthor() + local tag = entry.tag + ctx_btxsettag(tag) + -- local currentcitation = markcite(entry.dataset,tag) + -- ctx_btxsetbacklink(currentcitation) + -- local bl = listtocite[currentcitation] + -- ctx_btxsetinternal(bl and bl.references.internal or "") + ctx_btxsetfirst(entry[key] or f_missing(tag)) + ctx_btxsetthird(entry.suffix) + ctx_btxcitesetup(setup) + ctx_btxstopciteauthor() + ctx_btxstopsubcite() + end - local function setter(dataset,tag,entry,internal) - return { - dataset = dataset, - tag = tag, - internal = internal, - author = getauthor(dataset,tag,currentspecificationcategories), -- todo: list - } - end + local partialinteractive = false - local function getter(first,last,_,setup) - -- ctx_btxsetfirst(first.author) -- unformatted - ctx_btxsetfirst(currentbtxciteauthor) -- formatter (much slower) - return true - end + local function authorgetter(first,last,key,setup) -- only first + -- ctx_btxsetfirst(first.author) -- unformatted + ctx_btxsetfirst(currentbtxciteauthor) -- formatter (much slower) + local entries = first.entries + -- alternatively we can use a concat with one ... so that we can only make the + -- year interactive, as with the concat + if partialinteractive and not entries then + entries = { first } + end + if entries then + local c = compresslist(entries) + local f = function() authorconcat(c,key,setup) return true end -- indeed return true? + ctx_btxsetcount(#c) + ctx_btxsetsecond(f) + else + local f = function() authorsingle(first,key,setup) return true end -- indeed return true? + ctx_btxsetcount(0) + ctx_btxsetsecond(f) + end + return true + end - function citevariants.author(presets) - processcite(presets,{ - compress = false, - variant = "author", - setter = setter, - getter = getter, - }) - end + -- author - -- authornum + local function setter(dataset,tag,entry,internal) + return { + dataset = dataset, + tag = tag, + internal = internal, + author = getauthor(dataset,tag,currentspecification.categories), -- todo: list + } + end - local function setter(dataset,tag,entry,internal) - local text = entry.entries.text - return { - dataset = dataset, - tag = tag, - internal = internal, - author = getauthor(dataset,tag,currentspecificationcategories), -- todo: list - num = text, - sortkey = text and lpegmatch(numberonly,text), - } - end + local function getter(first,last,_,setup) + -- ctx_btxsetfirst(first.author) -- unformatted + ctx_btxsetfirst(currentbtxciteauthor) -- formatter (much slower) + return true + end - local function getter(first,last) - authorgetter(first,last,"num","author:num") - return true - end + function citevariants.author(presets) + processcite(presets,{ + compress = false, + variant = "author", + setter = setter, + getter = getter, + }) + end - function citevariants.authornum(presets) - processcite(presets,{ - variant = "authornum", - setter = setter, - getter = getter, - compressor = authorcompressor, - }) - end + -- authornum - -- authoryear | authoryears + local function setter(dataset,tag,entry,internal) + local text = entry.entries.text + return { + dataset = dataset, + tag = tag, + internal = internal, + author = getauthor(dataset,tag,currentspecification.categories), -- todo: list + num = text, + sortkey = text and lpegmatch(numberonly,text), + } + end - local function setter(dataset,tag,entry,internal) - return { - dataset = dataset, - tag = tag, - internal = internal, - author = getauthor(dataset,tag,currentspecificationcategories), -- todo: list - year = getfield(dataset,tag,"year"), - suffix = getdetail(dataset,tag,"suffix"), - sortkey = getdetail(dataset,tag,"suffixedyear"), - } - end + local function getter(first,last) + authorgetter(first,last,"num","author:num") + return true + end - local function getter(first,last) - authorgetter(first,last,"year","author:year") - return true - end + function citevariants.authornum(presets) + processcite(presets,{ + variant = "authornum", + setter = setter, + getter = getter, + compressor = authorcompressor, + }) + end - function citevariants.authoryear(presets) - processcite(presets,{ - variant = "authoryear", - setter = setter, - getter = getter, - compressor = authorcompressor, - }) - end + -- authoryear | authoryears - local function getter(first,last) - authorgetter(first,last,"year","author:years") - return true - end + local function setter(dataset,tag,entry,internal) + return { + dataset = dataset, + tag = tag, + internal = internal, + author = getauthor(dataset,tag,currentspecification.categories), -- todo: list + year = getfield(dataset,tag,"year"), + suffix = getdetail(dataset,tag,"suffix"), + sortkey = getdetail(dataset,tag,"suffixedyear"), + } + end - function citevariants.authoryears(presets) - processcite(presets,{ - variant = "authoryears", - setter = setter, - getter = getter, - compressor = authorcompressor, - }) - end + local function getter(first,last) + authorgetter(first,last,"year","author:year") + return true + end -end + function citevariants.authoryear(presets) + processcite(presets,{ + variant = "authoryear", + setter = setter, + getter = getter, + compressor = authorcompressor, + }) + end --- List variants + local function getter(first,last) + authorgetter(first,last,"year","author:years") + return true + end -local listvariants = { } -publications.listvariants = listvariants + function citevariants.authoryears(presets) + processcite(presets,{ + variant = "authoryears", + setter = setter, + getter = getter, + compressor = authorcompressor, + }) + end -function commands.btxlistvariant(dataset,block,tag,variant,listindex) - local action = listvariants[variant] or listvariants.default - if action then - action(dataset,block,tag,variant,tonumber(listindex) or 0) end -end -function listvariants.default(dataset,block,tag,variant) - ctx_btxsetfirst("?") - ctx_btxlistsetup(variant) end -function listvariants.num(dataset,block,tag,variant,listindex) - ctx_btxsetfirst(listindex) - ctx_btxlistsetup(variant) -end +-- List variants + +do -listvariants[v_yes] = listvariants.num -listvariants.bib = listvariants.num + local listvariants = { } + publications.listvariants = listvariants -function listvariants.short(dataset,block,tag,variant,listindex) - local short = getdetail(dataset,tag,"short","short") - local suffix = getdetail(dataset,tag,"suffix","suffix") - if short then - ctx_btxsetfirst(short) + function commands.btxlistvariant(dataset,block,tag,variant,listindex) + local action = listvariants[variant] or listvariants.default + if action then + action(dataset,block,tag,variant,tonumber(listindex) or 0) + end end - if suffix then - ctx_btxsetthird(suffix) + + function listvariants.default(dataset,block,tag,variant) + ctx_btxsetfirst("?") + ctx_btxlistsetup(variant) + end + + function listvariants.num(dataset,block,tag,variant,listindex) + ctx_btxsetfirst(listindex) + ctx_btxlistsetup(variant) end - ctx_btxlistsetup(variant) -end -function listvariants.page(dataset,block,tag,variant,listindex) - local rendering = renderings[dataset] - local specification = rendering.list[listindex] - for i=3,#specification do - local backlink = tonumber(specification[i]) - if backlink then - local citation = citetolist[backlink] - if citation then - local references = citation.references - if references then - local internal = references.internal - local realpage = references.realpage - if internal and realpage then - ctx_btxsetconcat(i-2) - ctx_btxsetfirst(realpage) - ctx_btxsetsecond(backlink) - ctx_btxlistsetup(variant) + listvariants[v_yes] = listvariants.num + listvariants.bib = listvariants.num + + function listvariants.short(dataset,block,tag,variant,listindex) + local short = getdetail(dataset,tag,"short","short") + local suffix = getdetail(dataset,tag,"suffix","suffix") + if short then + ctx_btxsetfirst(short) + end + if suffix then + ctx_btxsetthird(suffix) + end + ctx_btxlistsetup(variant) + end + + function listvariants.page(dataset,block,tag,variant,listindex) + local rendering = renderings[dataset] + local specification = rendering.list[listindex] + for i=3,#specification do + local backlink = tonumber(specification[i]) + if backlink then + local citation = citetolist[backlink] + if citation then + local references = citation.references + if references then + local internal = references.internal + local realpage = references.realpage + if internal and realpage then + ctx_btxsetconcat(i-2) + ctx_btxsetfirst(realpage) + ctx_btxsetsecond(backlink) + ctx_btxlistsetup(variant) + end end end end end end + end |