summaryrefslogtreecommitdiff
path: root/tex/context/base/mkxl/page-ini.lmt
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/mkxl/page-ini.lmt')
-rw-r--r--tex/context/base/mkxl/page-ini.lmt356
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,
+}