diff options
Diffstat (limited to 'Master/texmf-dist/tex/context/base/mkxl/page-lin.lmt')
-rw-r--r-- | Master/texmf-dist/tex/context/base/mkxl/page-lin.lmt | 418 |
1 files changed, 418 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/context/base/mkxl/page-lin.lmt b/Master/texmf-dist/tex/context/base/mkxl/page-lin.lmt new file mode 100644 index 00000000000..f50031ab300 --- /dev/null +++ b/Master/texmf-dist/tex/context/base/mkxl/page-lin.lmt @@ -0,0 +1,418 @@ +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" +} + +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 + +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 properties = nodes.properties.data + +local nodecodes = nodes.nodecodes +local hlist_code = nodecodes.hlist +local vlist_code = nodecodes.vlist +local whatsit_code = nodecodes.whatsit +local glyph_code = nodecodes.glyph + +local linelist_code = nodes.listcodes.line + +local latelua_code = nodes.whatsitcodes.latelua + +local localtexrun = tex.runlocal + +----- a_displaymath = attributes.private('displaymath') +local a_linenumber = attributes.private('linenumber') +local a_linereference = attributes.private('linereference') + +local cross_references = { } + +local nuts = nodes.nuts + +local getid = nuts.getid +local getattr = nuts.getattr +local getlist = nuts.getlist +local getbox = nuts.getbox +local gettotal = nuts.gettotal + +local takebox = nuts.takebox + +local nexthlist = nuts.traversers.hlist +local nextvlist = nuts.traversers.vlist +local nextcontent = nuts.traversers.content +local nextlist = nuts.traversers.list +local nextnode = nuts.traversers.node +local nextwhatsit = nuts.traversers.whatsit + +local is_display_math = nuts.is_display_math + +local ctx_convertnumber = context.convertnumber +local ctx_makelinenumber = context.makelinenumber + +local paragraphs = typesetters.paragraphs +local addtoline = paragraphs.addtoline +local checkline = paragraphs.checkline + +-- cross referencing + +function lines.number(n) + n = tonumber(n) + local cr = cross_references[n] or 0 + cross_references[n] = nil + return cr +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) + 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 + +local boxed = lines.boxed or { } +lines.boxed = 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 resolve(n,m) -- we can now check the 'line' flag (todo) + for current, id, subtype, content in nextlist, n do + if content then + if id == hlist_code then + for current, subtype in nextwhatsit, content do + if subtype == latelua_code then -- this has to change! + local a = getattr(current,a_linereference) + if a then + cross_references[a] = m + end + end + end + end + resolve(content,m) + end + end +end + +local function check_number(n,b,a,skip) + local d = data[a] + if d then + local tag = d.tag or "" + local s = d.start or 1 + local okay = not skip and s % d.step == 0 + if trace_numbers then + report_lines("%s number for setup %a, tag %a, line %s, continued %a",okay and "making" or "skipping",a,tag,s,d.continue or v_no) + end + if okay then + local p = checkline(n) + if p then + localtexrun(function() ctx_makelinenumber(tag,s,p.hsize,p.reverse and 1 or 0) end) + local l = takebox(b) + if l then + addtoline(n,l) + else + -- very unlikely + end + end + end + resolve(n,s) + d.start = s + 1 + 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 + +local function lineisnumbered(n) -- content node + for n, id, subtype, content in nextcontent, getlist(n) do + local a = getattr(n,a_linenumber) + if a and a > 0 then + return a + end + end +end + +local function listisnumbered(list) + if list then + for n, subtype in nexthlist, list do + if subtype == linelist_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 + for n, id, subtype, content in nextcontent, list do + if id == hlist_code then + if subtype == linelist_code then + local a = getattr(n,a_linenumber) + if a then + return a > 0 and list + end + return + else + if lineisnumbered(content) then + return n + end + local okay = findnumberedlist(content) + if okay then + return okay + end + end + elseif id == vlist_code then + if listisnumbered(content) then + return content + end + local okay = findnumberedlist(content) + if okay then + return okay + end + elseif id == glyph_code then + return + end + end +end + +-- reset ranges per page +-- store first and last per page +-- maybe just set marks directly + +local function findcolumngap(list) + -- we assume wrapped boxes, only one with numbers + for n, id, subtype, content in nextlist, list do + if id == hlist_code or id == vlist_code then + local p = properties[n] + if p and p.columngap then + if trace_numbers then + report_lines("first column gap %a",p.columngap) + end + return n + elseif content then + local okay = findcolumngap(content) + if okay then + return okay + end + end + end + end +end + +function boxed.addlinenumbers(n,b,nested) + local box = getbox(n) + if not box then + return + end + local list = getlist(box) + if not list then + return + end + local last_a = nil + local last_v = -1 + local skip = false + + local function check() + for n, subtype in nexthlist, list do + if subtype ~= linelist_code then + -- go on + elseif gettotal(n) == 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 + -- check_number(n,b,a,skip) + -- else + check_number(n,b,a,skip) + -- end + skip = false + end + end + end + end + + if nested == 0 then + if list then + check() + end + elseif nested == 1 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 + if list then + check() + end + elseif nested == 2 then + list = findcolumngap(list) + -- we assume we have a vlist + if not list then + return + end + for n in nextvlist, list do + local p = properties[n] + if p and p.columngap then + if trace_numbers then + report_lines("found column gap %a",p.columngap) + end + list = getlist(n) + if list then + check() + end + end + end + else + -- bad call + end +end + +-- column attribute + +implement { + name = "addlinenumbers", + actions = boxed.addlinenumbers, + arguments = { "integer", "integer", "integer" } +} |