summaryrefslogtreecommitdiff
path: root/tex/context/base/mkiv/node-syn.lua
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/mkiv/node-syn.lua')
-rw-r--r--tex/context/base/mkiv/node-syn.lua504
1 files changed, 504 insertions, 0 deletions
diff --git a/tex/context/base/mkiv/node-syn.lua b/tex/context/base/mkiv/node-syn.lua
new file mode 100644
index 000000000..1b8e07382
--- /dev/null
+++ b/tex/context/base/mkiv/node-syn.lua
@@ -0,0 +1,504 @@
+if not modules then modules = { } end modules ['node-syn'] = {
+ version = 1.001,
+ comment = "companion to node-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- Because we have these fields in some node that are used by sunctex, I decided (because
+-- some users seem to like that feature) to implement a variant that might work out better
+-- for ConTeXt. This is experimental code. I don't use it myself so it will take a while
+-- to mature. There will be some helpers that one can use in more complex situations like
+-- included xml files.
+--
+-- It is unclear how the output gets interpreted. For instance, we only need to be able to
+-- go back to a place where text is entered, but still we need all that redundant box
+-- wrapping.
+--
+-- Possible optimizations: pack whole lines.
+
+local type, rawset = type, rawset
+local concat = table.concat
+local formatters = string.formatters
+
+local trace = false trackers.register("system.syntex.visualize", function(v) trace = v end)
+
+local nuts = nodes.nuts
+local tonut = nuts.tonut
+local tonode = nuts.tonode
+
+local getid = nuts.getid
+local getlist = nuts.getlist
+local setlist = nuts.setlist
+local getnext = nuts.getnext
+local getwhd = nuts.getwhd
+local getwidth = nuts.getwidth
+local getsubtype = nuts.getsubtype
+local getattr = nuts.getattr
+
+local nodecodes = nodes.nodecodes
+local kerncodes = nodes.kerncodes
+
+local glue_code = nodecodes.glue
+local kern_code = nodecodes.kern
+local kern_disc = nodecodes.disc
+local rule_code = nodecodes.rule
+----- math_code = nodecodes.math
+local hlist_code = nodecodes.hlist
+local vlist_code = nodecodes.vlist
+local glyph_code = nodecodes.glyph
+local fontkern_code = kerncodes.fontkern
+
+local insert_before = nuts.insert_before
+local insert_after = nuts.insert_after
+
+local nodepool = nuts.pool
+local new_latelua = nodepool.latelua
+local new_rule = nodepool.rule
+local new_hlist = nodepool.hlist
+
+local getdimensions = nuts.dimensions
+local getrangedimensions = nuts.rangedimensions
+
+local a_fontkern = attributes.private("fontkern")
+
+local get_synctex_fields = nuts.get_synctex_fields
+local set_synctex_fields = nuts.set_synctex_fields
+local set_syntex_tag = nodes.set_synctex_tag
+
+local getcount = tex.getcount
+local setcount = tex.setcount
+
+local getpos = function()
+ getpos = backends.codeinjections.getpos
+ return getpos()
+ end
+
+local f_glue = formatters["g%i,%i:%i,%i"]
+local f_glyph = formatters["x%i,%i:%i,%i"]
+local f_kern = formatters["k%i,%i:%i,%i:%i"]
+local f_rule = formatters["r%i,%i:%i,%i:%i,%i,%i"]
+local f_hlist = formatters["[%i,%i:%i,%i:%i,%i,%i"]
+local f_vlist = formatters["(%i,%i:%i,%i:%i,%i,%i"]
+local s_hlist = "]"
+local s_vlist = ")"
+local f_hvoid = formatters["h%i,%i:%i,%i:%i,%i,%i"]
+local f_vvoid = formatters["v%i,%i:%i,%i:%i,%i,%i"]
+
+local characters = fonts.hashes.characters
+
+local synctex = { }
+luatex.synctex = synctex
+
+-- the file name stuff
+
+local noftags = 0
+local stnums = { }
+local sttags = table.setmetatableindex(function(t,name)
+ noftags = noftags + 1
+ t[name] = noftags
+ stnums[noftags] = name
+ return noftags
+end)
+
+function synctex.setfilename(name)
+ if set_syntex_tag and name then
+ set_syntex_tag(sttags[name])
+ end
+end
+
+function synctex.resetfilename()
+ if set_syntex_tag then
+ local name = luatex.currentfile()
+ if name then
+ set_syntex_tag(name)
+ end
+ end
+end
+
+-- the node stuff
+
+local result = { }
+local r = 0
+local f = nil
+local nofsheets = 0
+local nofobjects = 0
+local last = 0
+local filesdone = 0
+local enabled = false
+local compact = true
+
+local function writeanchor()
+ local size = f:seek("end")
+ f:write("!" .. (size-last) .. "\n")
+ last = size
+end
+
+local function writefiles()
+ local total = #stnums
+ if filesdone < total then
+ for i=filesdone+1,total do
+ f:write("Input:"..i..":"..stnums[i].."\n")
+ end
+ filesdone = total
+ end
+end
+
+local function flushpreamble()
+ local jobname = tex.jobname
+ stnums[0] = jobname
+ f = io.open(file.replacesuffix(jobname,"syncctx"),"w")
+ f:write("SyncTeX Version:1\n")
+ f:write("Input:0:"..jobname.."\n")
+ writefiles()
+ f:write("Output:pdf\n")
+ f:write("Magnification:1000\n")
+ f:write("Unit:1\n")
+ f:write("X Offset:0\n")
+ f:write("Y Offset:0\n")
+ f:write("Content:\n")
+ flushpreamble = writefiles
+end
+
+local function flushpostamble()
+ writeanchor()
+ f:write("Postamble:\n")
+ f:write("Count:"..nofobjects.."\n")
+ writeanchor()
+ f:write("Post scriptum:\n")
+ f:close()
+ enabled = false
+end
+
+local pageheight = 0 -- todo: set before we do this!
+
+local function b_hlist(head,current,t,l,w,h,d)
+ return insert_before(head,current,new_latelua(function()
+ local x, y = getpos()
+ r = r + 1
+ result[r] = f_hlist(t,l,x,tex.pageheight-y,w,h,d)
+ nofobjects = nofobjects + 1
+ end))
+end
+
+local function b_vlist(head,current,t,l,w,h,d)
+ return insert_before(head,current,new_latelua(function()
+ local x, y = getpos()
+ r = r + 1
+ result[r] = f_vlist(t,l,x,tex.pageheight-y,w,h,d)
+ nofobjects = nofobjects + 1
+ end))
+end
+
+local function e_hlist(head,current)
+ return insert_after(head,current,new_latelua(function()
+ r = r + 1
+ result[r] = s_hlist
+ nofobjects = nofobjects + 1
+ end))
+end
+
+local function e_vlist(head,current)
+ return insert_after(head,current,new_latelua(function()
+ r = r + 1
+ result[r] = s_vlist
+ nofobjects = nofobjects + 1
+ end))
+end
+
+local function x_hlist(head,current,t,l,w,h,d)
+ return insert_before(head,current,new_latelua(function()
+ local x, y = getpos()
+ r = r + 1
+ result[r] = f_hvoid(t,l,x,tex.pageheight-y,w,h,d)
+ nofobjects = nofobjects + 1
+ end))
+end
+
+local function x_vlist(head,current,t,l,w,h,d)
+ return insert_before(head,current,new_latelua(function()
+ local x, y = getpos()
+ r = r + 1
+ result[r] = f_vvoid(t,l,x,tex.pageheight-y,w,h,d)
+ nofobjects = nofobjects + 1
+ end))
+end
+
+-- local function x_glyph(head,current,t,l)
+-- return insert_before(head,current,new_latelua(function()
+-- local x, y = getpos()
+-- r = r + 1
+-- result[r] = f_glyph(t,l,x,tex.pageheight-y)
+-- nofobjects = nofobjects + 1
+-- end))
+-- end
+
+-- local function x_glue(head,current,t,l)
+-- return insert_before(head,current,new_latelua(function()
+-- local x, y = getpos()
+-- r = r + 1
+-- result[r] = f_glue(t,l,x,tex.pageheight-y)
+-- nofobjects = nofobjects + 1
+-- end))
+-- end
+
+-- local function x_kern(head,current,t,l,k)
+-- return insert_before(head,current,new_latelua(function()
+-- local x, y = getpos()
+-- r = r + 1
+-- result[r] = f_kern(t,l,x,tex.pageheight-y,k)
+-- nofobjects = nofobjects + 1
+-- end))
+-- end
+
+-- local function x_rule(head,current,t,l,w,h,d)
+-- return insert_before(head,current,new_latelua(function()
+-- local x, y = getpos()
+-- r = r + 1
+-- result[r] = f_rule(t,l,x,tex.pageheight-y,w,h,d)
+-- nofobjects = nofobjects + 1
+-- end))
+-- end
+
+local function collect(head,t,l)
+ local current = head
+ while current do
+ local id = getid(current)
+ if id == glyph_code then
+ local first = current
+ local last = current
+ while true do
+ id = getid(current)
+ if id == glyph_code or id == disc_code then
+ last = current
+ elseif id == kern_code and (getsubtype(current) == fontkern_code or getattr(current,a_fontkern)) then
+ last = current
+ else
+ if id == glue_code then
+ -- we could go on when we're in the same t/l run
+ local tc, lc = get_synctex_fields(current)
+ if tc > 0 then
+ t, l = tc, lc
+ end
+ id = nil -- so no test later on
+ end
+ local w, h, d = getdimensions(first,getnext(last))
+ -- local w, h, d = getrangedimensions(head,first,getnext(last))
+ if trace then
+ -- color is already handled so no colors
+ head = insert_before(head,first,new_hlist(new_rule(w,32768,32768)))
+ end
+if h < 655360 then
+ h = 655360
+end
+if d < 327680 then
+ d = 327680
+end
+ head = x_hlist(head,first,t,l,w,h,d)
+ break
+ end
+ current = getnext(current)
+ if not current then
+ local w, h, d = getdimensions(first,getnext(last))
+ -- local w, h, d = getrangedimensions(head,first,getnext(last))
+ if trace then
+ -- color is already handled so no colors
+ head = insert_before(head,first,new_hlist(new_rule(w,32768,32768)))
+ end
+if h < 655360 then
+ h = 655360
+end
+if d < 327680 then
+ d = 327680
+end
+ head = x_hlist(head,first,t,l,w,h,d)
+ return head
+ end
+ end
+ end
+ if id == hlist_code then
+ local list = getlist(current)
+ local tc, lc = get_synctex_fields(current)
+ if tc > 0 then
+ t, l = tc, lc
+ end
+ if compact then
+ if list then
+ local l = collect(list,t,l)
+ if l ~= list then
+ setlist(current,l)
+ end
+ end
+ else
+ local w, h, d = getwhd(current)
+ if w == 0 or (h == 0 and d == 0) then
+ if list then
+ local l = collect(list,t,l)
+ if l ~= list then
+ setlist(current,l)
+ end
+ end
+ elseif list then
+ -- head = b_hlist(head,current,t,l,w,h,d)
+ head = b_hlist(head,current,0,0,w,h,d)
+ local l = collect(list,t,l)
+ if l ~= list then
+ setlist(current,l)
+ end
+ head, current = e_hlist(head,current)
+ else
+ -- head = x_hlist(head,current,t,l,w,h,d)
+ head = x_hlist(head,current,0,0,w,h,d)
+ end
+ end
+ elseif id == vlist_code then
+ local list = getlist(current)
+ local tc, lc = get_synctex_fields(current)
+ if tc > 0 then
+ t, l = tc, lc
+ end
+ if compact then
+ if list then
+ local l = collect(list,t,l)
+ if l ~= list then
+ setlist(current,l)
+ end
+ end
+ else
+ local w, h, d = getwhd(current)
+ if w == 0 or (h == 0 and d == 0) then
+ if list then
+ local l = collect(list,t,l)
+ if l ~= list then
+ setlist(current,l)
+ end
+ end
+ elseif list then
+ -- head = b_vlist(head,current,t,l,w,h,d)
+ head = b_vlist(head,current,0,0,w,h,d)
+ local l = collect(list,t,l)
+ if l ~= list then
+ setlist(current,l)
+ end
+ head, current = e_vlist(head,current)
+ else
+ -- head = x_vlist(head,current,t,l,w,h,d)
+ head = x_vlist(head,current,0,0,w,h,d)
+ end
+ end
+ elseif id == glue_code then
+ local tc, lc = get_synctex_fields(current)
+ if tc > 0 then
+ t, l = tc, lc
+ end
+ -- head = x_glue(head,current,t,l)
+ -- elseif id == kern_code then
+ -- local tc, lc = get_synctex_fields(current)
+ -- if tc > 0 then
+ -- t, l = tc, lc
+ -- end
+ -- -- local k = getwidth(current)
+ -- -- if k ~= 0 then
+ -- -- head = x_kern(head,current,t,l,k)
+ -- -- end
+ -- elseif id == rule_code then
+ -- local tc, lc = get_synctex_fields(current)
+ -- if tc > 0 then
+ -- t, l = tc, lc
+ -- end
+ -- -- if t > 0 and l > 0 then
+ -- -- local w, h, d = getwhd(current)
+ -- -- head = x_rule(head,current,t,l,w,h,d)
+ -- -- end
+ end
+ current = getnext(current)
+ end
+ return head
+end
+
+-- range of same numbers
+
+function synctex.collect(head)
+ if enabled then
+ result, r = { }, 0
+ head = collect(tonut(head),0,0)
+ return tonode(head), true
+ else
+ return head, false
+ end
+end
+
+-- also no solution for bad first file resolving in sumatra
+
+function synctex.flush()
+ if enabled then
+ nofsheets = nofsheets + 1 -- could be realpageno
+ flushpreamble()
+ writeanchor()
+ f:write("{"..nofsheets.."\n")
+ if compact then
+ f:write(f_vlist(0,0,0,0,tex.pagewidth,tex.pageheight,0))
+ f:write("\n")
+ end
+ f:write(concat(result,"\n"))
+ if compact then
+ f:write("\n")
+ f:write(s_vlist)
+ end
+ f:write("\n")
+ writeanchor()
+ f:write("}"..nofsheets.."\n")
+ nofobjects = nofobjects + 2
+ result, r = { }, 0
+ end
+end
+
+function synctex.enable()
+ if not enabled and node.set_synctex_mode then
+ enabled = true
+ node.set_synctex_mode(1)
+ tex.normalsynctex = 0
+ nodes.tasks.appendaction("shipouts", "after", "nodes.synctex.collect")
+ end
+end
+
+function synctex.finish()
+ if enabled then
+ flushpostamble()
+ end
+end
+
+-- not the best place
+
+luatex.registerstopactions(synctex.finish)
+
+nodes.tasks.appendaction("shipouts", "after", "luatex.synctex.collect")
+
+-- moved here
+
+local report_system = logs.reporter("system")
+local synctex = false
+
+directives.register("system.synctex", function(v)
+ if v == "context" then
+ luatex.synctex.enable()
+ setcount("normalsynctex",0)
+ synctex = true
+ else
+ v = tonumber(v) or (toboolean(v,true) and 1) or (v == "zipped" and 1) or (v == "unzipped" and -1) or 0
+ setcount("normalsynctex",v)
+ synctex = v ~= 0
+ end
+ if synctex then
+ report_system("synctex functionality is enabled (%s), expect runtime overhead!",tostring(v))
+ else
+ report_system("synctex functionality is disabled!")
+ end
+end)
+
+statistics.register("synctex tracing",function()
+ if synctex or getcount("normalsynctex") ~= 0 then
+ return "synctex has been enabled (extra log file generated)"
+ end
+end)