summaryrefslogtreecommitdiff
path: root/tex/context/base/mkiv/page-lin.lua
diff options
context:
space:
mode:
authorContext Git Mirror Bot <phg42.2a@gmail.com>2016-01-12 17:15:07 +0100
committerContext Git Mirror Bot <phg42.2a@gmail.com>2016-01-12 17:15:07 +0100
commit8d8d528d2ad52599f11250cfc567fea4f37f2a8b (patch)
tree94286bc131ef7d994f9432febaf03fe23d10eef8 /tex/context/base/mkiv/page-lin.lua
parentf5aed2e51223c36c84c5f25a6cad238b2af59087 (diff)
downloadcontext-8d8d528d2ad52599f11250cfc567fea4f37f2a8b.tar.gz
2016-01-12 16:26:00
Diffstat (limited to 'tex/context/base/mkiv/page-lin.lua')
-rw-r--r--tex/context/base/mkiv/page-lin.lua462
1 files changed, 462 insertions, 0 deletions
diff --git a/tex/context/base/mkiv/page-lin.lua b/tex/context/base/mkiv/page-lin.lua
new file mode 100644
index 000000000..1124d80f9
--- /dev/null
+++ b/tex/context/base/mkiv/page-lin.lua
@@ -0,0 +1,462 @@
+if not modules then modules = { } end modules ['page-lin'] = {
+ version = 1.001,
+ comment = "companion to page-lin.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- experimental -> will become builders
+
+-- if there is demand for it, we can support multiple numbering streams
+-- and use more than one attibute
+
+local next, tonumber = next, tonumber
+
+local trace_numbers = false trackers.register("lines.numbers", function(v) trace_numbers = v end)
+
+local report_lines = logs.reporter("lines")
+
+local attributes = attributes
+local nodes = nodes
+local context = context
+
+local implement = interfaces.implement
+
+nodes.lines = nodes.lines or { }
+local lines = nodes.lines
+
+lines.data = lines.data or { } -- start step tag
+local data = lines.data
+local last = #data
+
+lines.scratchbox = lines.scratchbox or 0
+
+storage.register("lines/data", data, "nodes.lines.data")
+
+local variables = interfaces.variables
+
+local v_next = variables.next
+local v_page = variables.page
+local v_no = variables.no
+
+local nodecodes = nodes.nodecodes
+local skipcodes = nodes.skipcodes
+local whatcodes = nodes.whatcodes
+local listcodes = nodes.listcodes
+
+local hlist_code = nodecodes.hlist
+local vlist_code = nodecodes.vlist
+local whatsit_code = nodecodes.whatsit
+local glue_code = nodecodes.glue
+local glyph_code = nodecodes.glyph
+local line_code = listcodes.line
+local leftskip_code = skipcodes.leftskip
+
+local a_displaymath = attributes.private('displaymath')
+local a_linenumber = attributes.private('linenumber')
+local a_linereference = attributes.private('linereference')
+local a_verbatimline = attributes.private('verbatimline')
+
+local current_list = { }
+local cross_references = { }
+local chunksize = 250 -- not used in boxed
+
+local nuts = nodes.nuts
+
+local getid = nuts.getid
+local getsubtype = nuts.getsubtype
+local getnext = nuts.getnext
+local getattr = nuts.getattr
+local setattr = nuts.setattr
+local getlist = nuts.getlist
+local getbox = nuts.getbox
+local getfield = nuts.getfield
+
+local setprop = nuts.setprop
+local getprop = nuts.getprop
+
+local setfield = nuts.setfield
+
+local traverse_id = nuts.traverse_id
+local traverse = nuts.traverse
+local copy_node = nuts.copy
+local hpack_nodes = nuts.hpack
+local linked_nodes = nuts.linked
+local insert_node_after = nuts.insert_after
+local insert_node_before = nuts.insert_before
+local is_display_math = nuts.is_display_math
+local leftmarginwidth = nuts.leftmarginwidth
+
+local nodepool = nuts.pool
+local negated_glue = nodepool.negatedglue
+local new_hlist = nodepool.hlist
+local new_kern = nodepool.kern
+
+local ctx_convertnumber = context.convertnumber
+local ctx_makelinenumber = context.makelinenumber
+
+local paragraphs = typesetters.paragraphs
+local addtoline = paragraphs.addtoline
+local checkline = paragraphs.checkline
+local moveinline = paragraphs.moveinline
+
+-- cross referencing
+
+function lines.number(n)
+ n = tonumber(n)
+ local cr = cross_references[n] or 0
+ cross_references[n] = nil
+ return cr
+end
+
+local function resolve(n,m) -- we can now check the 'line' flag (todo)
+ while n do
+ local id = getid(n)
+ if id == whatsit_code then -- why whatsit
+ local a = getattr(n,a_linereference)
+ if a then
+ cross_references[a] = m
+ end
+ elseif id == hlist_code or id == vlist_code then
+ resolve(getlist(n),m)
+ end
+ n = getnext(n)
+ end
+end
+
+function lines.finalize(t)
+ local getnumber = lines.number
+ for _,p in next, t do
+ for _,r in next, p do
+ local m = r.metadata
+ if m and m.kind == "line" then
+ local e = r.entries
+ local u = r.userdata
+ e.linenumber = getnumber(e.text or 0) -- we can nil e.text
+ e.conversion = u and u.conversion
+ r.userdata = nil -- hack
+ end
+ end
+ end
+end
+
+local filters = structures.references.filters
+local helpers = structures.helpers
+
+structures.references.registerfinalizer(lines.finalize)
+
+filters.line = filters.line or { }
+
+function filters.line.default(data)
+-- helpers.title(data.entries.linenumber or "?",data.metadata)
+ ctx_convertnumber(data.entries.conversion or "numbers",data.entries.linenumber or "0")
+end
+
+function filters.line.page(data,prefixspec,pagespec) -- redundant
+ helpers.prefixpage(data,prefixspec,pagespec)
+end
+
+function filters.line.linenumber(data) -- raw
+ context(data.entries.linenumber or "0")
+end
+
+-- boxed variant, todo: use number mechanism
+
+lines.boxed = { }
+local boxed = lines.boxed
+
+-- todo: cache setups, and free id no longer used
+-- use interfaces.cachesetup(t)
+
+function boxed.register(configuration)
+ last = last + 1
+ data[last] = configuration
+ if trace_numbers then
+ report_lines("registering setup %a",last)
+ end
+ return last
+end
+
+implement {
+ name = "registerlinenumbering",
+ actions = { boxed.register, context },
+ arguments = {
+ {
+ { "continue" },
+ { "start", "integer" },
+ { "step", "integer" },
+ { "method" },
+ { "tag" },
+ }
+ }
+}
+
+function boxed.setup(n,configuration)
+ local d = data[n]
+ if d then
+ if trace_numbers then
+ report_lines("updating setup %a",n)
+ end
+ for k,v in next, configuration do
+ d[k] = v
+ end
+ else
+ if trace_numbers then
+ report_lines("registering setup %a (br)",n)
+ end
+ data[n] = configuration
+ end
+ return n
+end
+
+implement {
+ name = "setuplinenumbering",
+ actions = boxed.setup,
+ arguments = {
+ "integer",
+ {
+ { "continue" },
+ { "start", "integer" },
+ { "step", "integer" },
+ { "method" },
+ { "tag" },
+ }
+ }
+}
+
+local function check_number(n,a,skip,sameline)
+ local d = data[a]
+ if d then
+ local tag, skipflag, s = d.tag or "", 0, d.start or 1
+ current_list[#current_list+1] = { n, s }
+ if sameline then
+ skipflag = 0
+ if trace_numbers then
+ report_lines("skipping broken line number %s for setup %a: %s (%s)",#current_list,a,s,d.continue or v_no)
+ end
+ elseif not skip and s % d.step == 0 then
+ skipflag, d.start = 1, s + 1 -- (d.step or 1)
+ if trace_numbers then
+ report_lines("making number %s for setup %a: %s (%s)",#current_list,a,s,d.continue or v_no)
+ end
+ else
+ skipflag, d.start = 0, s + 1 -- (d.step or 1)
+ if trace_numbers then
+ report_lines("skipping line number %s for setup %a: %s (%s)",#current_list,a,s,d.continue or v_no)
+ end
+ end
+ local p = checkline(n)
+ if p then
+ ctx_makelinenumber(tag,skipflag,s,p.hsize,p.reverse and "TRT" or "TLT")
+ else
+ report_lines("needs checking")
+ end
+ end
+end
+
+-- print(nodes.idstostring(list))
+
+-- hlists of type line will only have an attribute when the line number attribute
+-- still set at par building time which is not always the case unless we explicitly
+-- do a par before we end the line
+
+-- todo: check for a: when <= 0 then false
+
+local function lineisnumbered(n)
+ local n = getlist(n)
+ while n do
+ local id = getid(n)
+ if id == hlist_code or id == vlist_code then
+ -- this can hit fast as we inherit anchor attributes from parent
+ local a = getattr(n,a_linenumber)
+ if a and a > 0 then
+ return a
+ end
+ elseif id == glyph_code then
+ local a = getattr(n,a_linenumber)
+ if a and a > 0 then
+ return a
+ else
+ return false
+ end
+ end
+ n = getnext(n)
+ end
+end
+
+local function listisnumbered(list)
+ if list then
+ for n in traverse_id(hlist_code,list) do
+ if getsubtype(n) == line_code then
+ local a = getattr(n,a_linenumber)
+ if a then
+ -- a quick test for lines (only valid when \par before \stoplinenumbering)
+ return a > 0 and list or false
+ else
+ -- a bit slower one, assuming that we have normalized and anchored
+ if lineisnumbered(n) then
+ return list
+ end
+ end
+ end
+ end
+ end
+end
+
+local function findnumberedlist(list)
+ -- we assume wrapped boxes, only one with numbers
+ local n = list
+ while n do
+ local id = getid(n)
+ if id == hlist_code then
+ if getsubtype(n) == line_code then
+ local a = getattr(n,a_linenumber)
+ if a then
+ return a > 0 and list
+ end
+ return
+ else
+ local list = getlist(n)
+ if lineisnumbered(list) then
+ return n
+ end
+ local okay = findnumberedlist(list)
+ if okay then
+ return okay
+ end
+ end
+ elseif id == vlist_code then
+ local list = getlist(n)
+ if listisnumbered(list) then
+ return list
+ end
+ local okay = findnumberedlist(list)
+ if okay then
+ return okay
+ end
+ elseif id == glyph_code then
+ return
+ end
+ n = getnext(n)
+ end
+end
+
+-- reset ranges per page
+-- store first and last per page
+-- maybe just set marks directly
+
+function boxed.stage_one(n,nested)
+ current_list = { }
+ local box = getbox(n)
+ if box then
+ local list = getlist(box)
+ if not list then
+ return
+ end
+ if nested then
+ local id = getid(box)
+ if id == vlist_code then
+ if listisnumbered(list) then
+ -- ok
+ else
+ list = findnumberedlist(list)
+ end
+ else -- hlist
+ list = findnumberedlist(list)
+ end
+ end
+ -- we assume we have a vlist
+ if list then
+ local last_a = nil
+ local last_v = -1
+ local skip = false
+ for n in traverse_id(hlist_code,list) do -- attr test here and quit as soon as zero found
+ local subtype = getsubtype(n)
+ if subtype ~= line_code then
+ -- go on
+ elseif getfield(n,"height") == 0 and getfield(n,"depth") == 0 then
+ -- skip funny hlists -- todo: check line subtype
+ else
+ local a = lineisnumbered(n)
+ if a then
+ if last_a ~= a then
+ local da = data[a]
+ local ma = da.method
+ if ma == v_next then
+ skip = true
+ elseif ma == v_page then
+ da.start = 1 -- eventually we will have a normal counter
+ end
+ last_a = a
+ if trace_numbers then
+ report_lines("starting line number range %s: start %s, continue %s",a,da.start,da.continue or v_no)
+ end
+ end
+ if getattr(n,a_displaymath) then
+ if is_display_math(n) then
+ check_number(n,a,skip)
+ end
+ else
+ local v = getattr(list,a_verbatimline)
+ if not v or v ~= last_v then
+ last_v = v
+ check_number(n,a,skip)
+ else
+ check_number(n,a,skip,true)
+ end
+ end
+ skip = false
+ end
+ end
+ end
+ end
+ end
+end
+
+function boxed.stage_two(n,m)
+ if #current_list > 0 then
+ m = m or lines.scratchbox
+ local t, tn = { }, 0
+ for l in traverse_id(hlist_code,getlist(getbox(m))) do
+ tn = tn + 1
+ t[tn] = copy_node(l) -- use take_box instead
+ end
+ for i=1,#current_list do
+ local li = current_list[i]
+ local n, m, ti = li[1], li[2], t[i]
+ if ti then
+ -- local d = getfield(n,"dir")
+ -- local l = getlist(n)
+ -- if d == "TRT" then
+ -- local w = getfield(n,"width")
+ -- ti = hpack_nodes(linked_nodes(new_kern(-w),ti,new_kern(w)))
+ -- end
+ -- setnext(ti,l)
+ -- setprev(l,ti)
+ -- setlist(n,ti)
+ addtoline(n,ti)
+ resolve(n,m)
+ else
+ report_lines("error in linenumbering (1)")
+ return
+ end
+ end
+ end
+end
+
+-- function boxed.stage_zero(n) -- not used
+-- return identify(getlist(getbox(n)))
+-- end
+
+implement {
+ name = "linenumbersstageone",
+ actions = boxed.stage_one,
+ arguments = { "integer", "boolean" }
+}
+
+implement {
+ name = "linenumbersstagetwo",
+ actions = boxed.stage_two,
+ arguments = { "integer", "integer" }
+}