diff options
Diffstat (limited to 'tex/context/base/mkxl/page-ini.lmt')
-rw-r--r-- | tex/context/base/mkxl/page-ini.lmt | 356 |
1 files changed, 356 insertions, 0 deletions
diff --git a/tex/context/base/mkxl/page-ini.lmt b/tex/context/base/mkxl/page-ini.lmt new file mode 100644 index 000000000..bb5ea2b5d --- /dev/null +++ b/tex/context/base/mkxl/page-ini.lmt @@ -0,0 +1,356 @@ +if not modules then modules = { } end modules ['page-ini'] = { + version = 1.001, + comment = "companion to page-ini.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- Some day I need to make this more efficient. + +local tonumber, rawget, rawset, type, next = tonumber, rawget, rawset, type, next +local match = string.match +local sort, tohash, insert, remove, sortedkeys = table.sort, table.tohash, table.insert, table.remove, table.sortedkeys +local settings_to_array, settings_to_hash = utilities.parsers.settings_to_array, utilities.parsers.settings_to_hash + +local texgetcount = tex.getcount + +local tonut = nodes.tonut +local nextlist = nodes.nuts.traversers.list +local texlists = tex.lists + +local context = context +local ctx_doif = commands.doif +local ctx_doifelse = commands.doifelse + +local implement = interfaces.implement + +local data = table.setmetatableindex("table") +local last = 0 +local pages = structures.pages +local autolist = { } +local report = logs.reporter("pages","mark") +local active = false + +local trace = false trackers.register("pages.mark",function(v) trace = v end) + +function pages.mark(name,list,settings) + active = true + -- + local realpage = texgetcount("realpageno") + if type(settings) == "string" then + settings = settings_to_hash(settings) + end + if not list or list == "" then + if trace then + report("marking current page %i as %a",realpage,name) + end + data[realpage][name] = settings or true + return + end + if type(list) == "string" then + list = settings_to_array(list) + end + if type(list) == "table" then + for i=1,#list do + local page = list[i] + local sign = false + if type(page) == "string" then + local f, t = match(page,"(%d+)[:%-](%d+)") + if f and t then + f, t = tonumber(f), tonumber(t) + if f and t and f <= t then + if trace then + report("marking page %i upto %i as %a",f,t,name) + end + for page=f,t do + data[page][name] = settings or true + end + end + page = false + else + local s, p = match(page,"([%+%-])(%d+)") + if s then + sign, page = s, p + end + end + end + if page then + page = tonumber(page) + if page then + if sign == "+" then + page = realpage + page + end + if sign == "-" then + report("negative page numbers are not supported") + else + if trace then + report("marking page %i as %a",page,name) + end + data[page][name] = settings or true + end + end + end + end + else + if trace then + report("marking current page %i as %a",realpage,name) + end + data[realpage][name] = settings or true + end +end + +local tobemarked = { } + +function pages.markedlist(realpage) + if active and realpage then + local m = rawget(tobemarked,realpage) or rawget(data,realpage) + return m and next(m) and sortedkeys(m) + end +end + +local function marked(name) + if active then + local realpage = texgetcount("realpageno") + if last ~= 0 then + for i=last,realpage-1 do + -- print(last) + local di = data[i] + if di then + tobemarked[i] = di + rawset(data,i,nil) + end + end + last = 0 -- needs checking + end + local pagedata = rawget(data,realpage) + return pagedata and pagedata[name] and true or false + else + return false + end +end + +local function markedparameter(name,key) + if active then + local pagedata = rawget(data,texgetcount("realpageno")) + if pagedata then + pagedata = pagedata[name] + if pagedata then + pagedata = pagedata[key] + end + end + return pagedata + end +end + +local function toranges(marked) + local list = { } + local size = #marked + if size > 0 then + local first = marked[1] + local last = first + for i=2,size do + local page = marked[i] + if page > last + 1 then + list[#list+1] = { first, last } + first = page + end + last = page + end + list[#list+1] = { first, last } + -- + active = true + end + return list +end + +local function allmarked(list) + if active and list then + local collected = pages.collected + if collected then + if type(list) == "string" then + list = settings_to_hash(list) + elseif type(list) == "table" and #list > 0 then + list = tohash(list) + end + if type(list) == "table" then + local found = { } + for name in next, list do + for page, list in next, data do + if list[name] and collected[page] then + found[#found+1] = page + end + end + end + if #found > 0 then + sort(found) + if trace then + local ranges = toranges(found) + for i=1,#ranges do + local range = ranges[i] + local first = range[1] + local last = range[2] + if first == last then + report("marked page : %i",first) + else + report("marked range: %i upto %i",first,last) + end + end + end + return found + end + end + end + end +end + +pages.marked = marked +pages.toranges = toranges +pages.allmarked = allmarked + +-- An alternative is to use an attribute and identify the state by parsing the node +-- list but that's a bit overkill for a hardly used feature like this. + +-- Page actions are bound to a real page. When we set one, we need to bind to the +-- current page unless we just flushed. So we also need to check the current page. + +-- \page ... \start : sync realpage +-- \page \start : sync realpage +-- \page \stop : reset synced because no content yet +-- \page ... \stop : keep sync + +local function autopageaction() + if active then + local nofauto = #autolist + if nofauto > 0 then + local realpage = texgetcount("realpageno") + for i=1,nofauto do + local entry = autolist[i] + local names = entry[1] + local settings = entry[2] + for j=1,#names do + local name = names[j] + local list = data[realpage] + if not list[name] then + if trace then + report("automatically marking page %i as %a",realpage,name) + end + list[name] = settings or true + end + end + end + end + end +end + +local function startmarked(name,settings) + active = true + -- + insert(autolist, { settings_to_array(name), settings_to_hash(settings) }) + autopageaction(true) +end + +local function stopmarked() + local nofauto = #autolist + if nofauto > 0 then + if not texlists.pagehead then + local realpage = texgetcount("realpageno") + for i=1,nofauto do + local entry = autolist[i] + local names = entry[1] + for j=1,#names do + local name = names[j] + local list = data[realpage] + if list[name] then + if trace then + report("automatically unmarking page %i as %a",realpage,name) + end + list[name] = nil + end + end + end + end + remove(autolist) + end +end + +implement { + name = "checkmarkedpages", + protected = true, + public = true, + actions = autopageaction, +} + +implement { + name = "markpage", + arguments = "3 strings", + actions = pages.mark +} + +implement { + name = "doifelsemarkedpage", + arguments = "argument", + protected = true, + public = true, + actions = { marked, ctx_doifelse } +} + +implement { + name = "doifmarkedpage", + arguments = "argument", + protected = true, + public = true, + actions = { marked, ctx_doif } +} + +implement { + name = "markedpageparameter", + arguments = "2 arguments", + public = true, + actions = function(name,key) + local value = markedparameter(name,key) + if value then + context(value) + end + end +} + +implement { + name = "markedpages", + arguments = "string", + actions = function(name) + local t = allmarked(name) + if t then + context("%,t",t) + end + end +} + +implement { + name = "startmarkpages", + arguments = "2 strings", + actions = startmarked, +} + +implement { + name = "stopmarkpages", + protected = true, + public = true, + actions = stopmarked, +} + +implement { + name = "doifelsependingpagecontent", + actions = function() + local h = texlists.contrib_head + -- local t = texlists.contrib_tail + local p = false + if h then + for n in nextlist, tonut(h) do + p = true + break + end + end + ctx_doifelse(p) + end, +} |