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 local format = string.format local texsprint, texbox = tex.sprint, tex.box local ctxcatcodes = tex.ctxcatcodes nodes = nodes or { } nodes.lines = nodes.lines or { } nodes.lines.data = nodes.lines.data or { } -- start step tag -- if there is demand for it, we can support multiple numbering streams -- and use more than one attibute local hlist, vlist, whatsit = node.id('hlist'), node.id('vlist'), node.id('whatsit') local display_math = attributes.private('display-math') local line_number = attributes.private('line-number') local line_reference = attributes.private('line-reference') local current_list = { } local cross_references = { } local chunksize = 250 -- not used in boxed local has_attribute = node.has_attribute local traverse_id = node.traverse_id local traverse = node.traverse local copy_node = node.copy local data = nodes.lines.data nodes.lines.scratchbox = nodes.lines.scratchbox or 0 -- cross referencing function nodes.lines.number(n) local cr = cross_references[n] or 0 cross_references[n] = nil return cr end local function resolve(n,m) while n do local id = n.id if id == whatsit then local a = has_attribute(n,line_reference) if a then cross_references[a] = m end elseif id == hlist or id == vlist then resolve(n.list,m) end n = n.next end end -- boxed variant nodes.lines.boxed = { } function nodes.lines.boxed.register(configuration) data[#data+1] = configuration return #data end function nodes.lines.boxed.setup(n,configuration) local d = data[n] if d then for k,v in pairs(configuration) do d[k] = v end else data[n] = configuration end return n end local leftskip = nodes.leftskip local function check_number(n,a) -- move inline local d = data[a] if d then local s = d.start current_list[#current_list+1] = { n, s } if d.start % d.step == 0 then texsprint(ctxcatcodes, format("\\makenumber{%s}{%s}{%s}{%s}{%s}\\endgraf", d.tag or "", s, n.shift, n.width, leftskip(n.list))) else texsprint(ctxcatcodes, "\\skipnumber\\endgraf") end d.start = s + 1 -- (d.step or 1) end end function nodes.lines.boxed.stage_one(n) current_list = { } local head = texbox[n] if head then local list = head.list --~ while list.id == vlist and not list.next do --~ list = list.list --~ end for n in traverse_id(hlist,list) do -- attr test here and quit as soon as zero found if n.height == 0 and n.depth == 0 then -- skip funny hlists else local a = has_attribute(n.list,line_number) if a and a > 0 then if has_attribute(n,display_math) then if nodes.is_display_math(n) then check_number(n,a) end else if node.first_character(n.list) then check_number(n,a) end end end end end end end function nodes.lines.boxed.stage_two(n,m) if #current_list > 0 then m = m or nodes.lines.scratchbox local t, i = { }, 0 for l in traverse_id(hlist,texbox[m].list) do t[#t+1] = copy_node(l) end for j=1,#current_list do local l = current_list[j] local n, m = l[1], l[2] i = i + 1 t[i].next = n.list n.list = t[i] resolve(n,m) end end end -- flow variant -- -- it's too hard to make this one robust, so for the moment it's not -- available; todo: line refs if false then nodes.lines.flowed = { } function nodes.lines.flowed.prepare(tag) for i=1,#data do -- ?? texsprint(ctxcatcodes,format("\\ctxlua{nodes.lines.flowed.prepare_a(%s)}\\ctxlua{nodes.lines.flowed.prepare_b(%s)}",i,i)) end end function nodes.lines.flowed.prepare_a(i) local d = data[i] local p = d.present if p and p < chunksize then local b = nodes.lines.scratchbox texsprint(ctxcatcodes, format("{\\forgetall\\global\\setbox%s=\\vbox{\\unvbox%s\\relax\\offinterlineskip", b, b)) while p < chunksize do texsprint(ctxcatcodes, format("\\mkmaketextlinenumber{%s}{%s}\\endgraf",d.start,1)) p = p + 1 d.start = d.start + d.step end d.present = p texsprint(ctxcatcodes, "}}") end end function nodes.lines.flowed.prepare_b(i) local d = data[i] local b = nodes.lines.scratchbox local l = texbox[b] if l then l = l.list local n = d.numbers while l do if l.id == hlist then local m = copy_node(l) m.next = nil if n then n.next = m else d.numbers = m end n = m end l = l.next end end tex.box[b] = nil end function nodes.lines.flowed.cleanup(i) if i then node.flush_list(data[i].numbers) else for i=1,#data do node.flush_list(data[i].numbers) end end end local function check_number(n,a) local d = data[a] if d then local m = d.numbers if m then d.numbers = m.next m.next = n.list n.list = m d.present = d.present - 1 end end end function nodes.lines.flowed.apply(head) for n in node.traverse(head) do local id = n.id if id == hlist then if n.height == 0 and n.depth == 0 then -- skip funny hlists else local a = has_attribute(n,line_number) if a and a > 0 then if has_attribute(n,display_math) then if nodes.is_display_math(n) then check_number(n,a) end else check_number(n,a) end end end end end return head, true end end