diff options
Diffstat (limited to 'tex/context/base/mkiv/node-syn.lua')
-rw-r--r-- | tex/context/base/mkiv/node-syn.lua | 922 |
1 files changed, 607 insertions, 315 deletions
diff --git a/tex/context/base/mkiv/node-syn.lua b/tex/context/base/mkiv/node-syn.lua index 1b8e07382..9d716c44a 100644 --- a/tex/context/base/mkiv/node-syn.lua +++ b/tex/context/base/mkiv/node-syn.lua @@ -6,23 +6,124 @@ if not modules then modules = { } end modules ['node-syn'] = { 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. +-- Because we have these fields in some node that are used by synctex, and because +-- some users seem to like that feature, I decided 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. Currently (somewhere else) we +-- take care of valid files, that is: we prohibit access to files in the tree +-- because we don't want users to mess up styles. -- --- 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. +-- It is unclear how the output gets interpreted but by reverse engineering (and +-- stripping) the file generated by generic synctex, I got there eventually. 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. Anyway, I was able to get a +-- minimal output and cross my fingers that the parser used in editors is not +-- changed in fundamental ways. -- --- Possible optimizations: pack whole lines. +-- I only tested SumatraPDF with SciTE, for which one needs to configure in the +-- viewer: +-- +-- InverseSearchCmdLine = c:\data\system\scite\wscite\scite.exe "%f" "-goto:%l" $ +-- +-- Unfortunately syntex always removes the files at the end and not at the start +-- (this happens in synctexterminate) so we need to work around that by using an +-- intermediate file. This is no big deal in context (which has a runner) but +-- definitely not nice. +-- +-- The visualizer code is only needed for testing so we don't use fancy colors or +-- provide more detail. After all we're only interested in rendered source text +-- anyway. We try to play safe which sometimes means that we'd better no go +-- somewhere than go someplace wrong. +-- +-- A previous version had a mode for exporting boxes and such but I removed that +-- as it made no sense. Also, collecting output in a table was not faster than +-- directly piping to the file, probably because the amount is not that large. We +-- keep some left-overs commented. +-- +-- A significate reduction in file size can be realized when reusing the same +-- values. Actually that triggered the current approach in ConTeXt. In the latest +-- synctex parser vertical positions can be repeated by an "=" sign but for some +-- reason only for that field. It's probably trivial to do that for all of "w h d v +-- h" but it currently not the case so I'll delay that till all are supported. (We +-- could benefit a lot from such a repetition scheme but not much from a "v" alone +-- which -alas- indicates that synctex is still mostly a latex targeted story.) +-- +-- It's kind of hard to fight the parser because it really wants to go to some file +-- but maybe some day I can figure it out. Some untagged text (in the pdf) somehow +-- gets seen as part of the last box. Anonymous content is simply not part of the +-- concept. Using a dummy name doesn't help either as the editor gets a signal to +-- open that dummy. Even an empty filename doesn't work. +-- +-- We output really simple and compact code, like: +-- +-- SyncTeX Version:1 +-- Input:1:e:/tmp/oeps.tex +-- Input:2:c:/data/develop/context/sources/klein.tex +-- Output:pdf +-- Magnification:1000 +-- Unit:1 +-- X Offset:0 +-- Y Offset:0 +-- Content: +-- !160 +-- {1 +-- h0,0:0,0,0,0,0 +-- v0,0:0,55380990:39158276,55380990,0 +-- h2,1:4661756,9176901:27969941,655360,327680 +-- h2,2:4661756,10125967:26048041,655360,327680 +-- h2,3:30962888,10125967:1668809,655360,327680 +-- h2,3:4661756,11075033:23142527,655360,327680 +-- h2,4:28046650,11075033:4585047,655360,327680 +-- h2,4:4661756,12024099:22913954,655360,327680 +-- h2,5:27908377,12024099:4723320,655360,327680 +-- h2,5:4661756,12973165:22918783,655360,327680 +-- h2,6:27884864,12973165:4746833,655360,327680 +-- h2,6:4661756,13922231:18320732,655360,327680 +-- ) +-- ] +-- !533 +-- }1 +-- Input:3:c:/data/develop/context/sources/ward.tex +-- !57 +-- {2 +-- h0,0:0,0,0,0,0 +-- v0,0:0,55380990:39158276,55380990,0 +-- h3,1:4661756,9176901:18813145,655360,327680 +-- h3,2:23713999,9176901:8917698,655360,327680 +-- h3,2:4661756,10125967:10512978,655360,327680 +-- h3,3:15457206,10125967:17174491,655360,327680 +-- h3,3:4661756,11075033:3571223,655360,327680 +-- h3,4:8459505,11075033:19885281,655360,327680 +-- h3,5:28571312,11075033:4060385,655360,327680 +-- h3,5:4661756,12024099:15344870,655360,327680 +-- ) +-- ] +-- !441 +-- }2 +-- !8 +-- Postamble: +-- Count:22 +-- !23 +-- Post scriptum: +-- +-- But for some reason, when the pdf file has some extra content (like page numbers) +-- the main document is consulted. Bah. It would be nice to have a mode for *only* +-- looking at marked areas. It somehow works not but maybe depends on the parser. +-- +-- Supporting reuseable objects makes not much sense as these are often graphics or +-- ornamental. They can not have hyperlinks etc (at least not without some hackery +-- which I'm not willing to do) so basically they are sort of useless for text. local type, rawset = type, rawset local concat = table.concat local formatters = string.formatters +local replacesuffix, suffixonly, nameonly = file.replacesuffix, file.suffix, file.nameonly +local openfile, renamefile, removefile = io.open, os.rename, os.remove + +local report_system = logs.reporter("system") -local trace = false trackers.register("system.syntex.visualize", function(v) trace = v end) +local tex = tex local nuts = nodes.nuts local tonut = nuts.tonut @@ -35,19 +136,18 @@ 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 glyph_code = nodecodes.glyph +local disc_code = nodecodes.disc local glue_code = nodecodes.glue +local penalty_code = nodecodes.penalty local kern_code = nodecodes.kern -local kern_disc = nodecodes.disc -local rule_code = nodecodes.rule ------ math_code = nodecodes.math +----- rule_code = nodecodes.rule 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 @@ -56,82 +156,131 @@ 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 new_kern = nodepool.kern 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 set_synctex_line = tex.set_synctex_line +local set_synctex_tag = tex.set_synctex_tag +local force_synctex_tag = tex.force_synctex_tag +local force_synctex_line = tex.force_synctex_line +----- get_synctex_tag = tex.get_synctex_tag +----- get_synctex_line = tex.get_synctex_line +local set_synctex_mode = tex.set_synctex_mode 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 foundintree = resolvers.foundintree + +local eol = "\010" + +----- f_glue = formatters["g%i,%i:%i,%i\010"] +----- f_glyph = formatters["x%i,%i:%i,%i\010"] +----- f_kern = formatters["k%i,%i:%i,%i:%i\010"] +----- f_rule = formatters["r%i,%i:%i,%i:%i,%i,%i\010"] +----- f_form = formatters["f%i,%i,%i\010"] +local z_hlist = "[0,0:0,0:0,0,0\010" +local z_vlist = "(0,0:0,0:0,0,0\010" +----- z_xform = "<0,0:0,0,0\010" -- or so +local s_hlist = "]\010" +local s_vlist = ")\010" +----- s_xform = ">\010" +local f_hlist_1 = formatters["h%i,%i:%i,%i:%i,%i,%i\010"] +local f_hlist_2 = formatters["h%i,%i:%i,%s:%i,%i,%i\010"] +local f_vlist_1 = formatters["v%i,%i:%i,%i:%i,%i,%i\010"] +local f_vlist_2 = formatters["v%i,%i:%i,%s:%i,%i,%i\010"] + +local synctex = luatex.synctex or { } +luatex.synctex = synctex -local characters = fonts.hashes.characters +-- status stuff -local synctex = { } -luatex.synctex = synctex +local enabled = false +local paused = 0 +local used = false +local never = false + +-- get rid of overhead + +if tex.set_synctex_no_files then + tex.set_synctex_no_files(1) +end -- 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 +local nofblocked = 0 +local blockedfilenames = { } +local blockedsuffixes = { + mkii = true, + mkiv = true, + mkvi = true, + mkix = true, + mkxi = true, + -- lfg = true, +} + +local sttags = table.setmetatableindex(function(t,name) + if blockedsuffixes[suffixonly(name)] then + -- Just so that I don't get the ones on my development tree. + nofblocked = nofblocked + 1 + return 0 + elseif blockedfilenames[nameonly(name)] then + -- So we can block specific files. + nofblocked = nofblocked + 1 + return 0 + elseif foundintree(name) then + -- One shouldn't edit styles etc this way. + nofblocked = nofblocked + 1 + return 0 + else + noftags = noftags + 1 + t[name] = noftags + stnums[noftags] = name + return noftags + end end) -function synctex.setfilename(name) - if set_syntex_tag and name then - set_syntex_tag(sttags[name]) +function synctex.blockfilename(name) + blockedfilenames[nameonly(name)] = name +end + +function synctex.setfilename(name,line) + if paused == 0 and force_synctex_tag and name then + force_synctex_tag(sttags[name]) + if line then + force_synctex_line(line) + end end end function synctex.resetfilename() - if set_syntex_tag then - local name = luatex.currentfile() - if name then - set_syntex_tag(name) - end + if paused == 0 and force_synctex_tag then + force_synctex_tag(0) + force_synctex_line(0) 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 filehandle = nil +local nofsheets = 0 +local nofobjects = 0 +local last = 0 +local filesdone = 0 +local tmpfile = false +local logfile = false local function writeanchor() - local size = f:seek("end") - f:write("!" .. (size-last) .. "\n") + local size = filehandle:seek("end") + filehandle:write("!",size-last,eol) last = size end @@ -139,291 +288,349 @@ local function writefiles() local total = #stnums if filesdone < total then for i=filesdone+1,total do - f:write("Input:"..i..":"..stnums[i].."\n") + filehandle:write("Input:",i,":",stnums[i],eol) end filesdone = total end end +local function makenames() + logfile = replacesuffix(tex.jobname,"synctex") + tmpfile = replacesuffix(logfile,"syncctx") +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 + makenames() + filehandle = openfile(tmpfile,"wb") + if filehandle then + filehandle:write("SyncTeX Version:1",eol) + writefiles() + filehandle:write("Output:pdf",eol) + filehandle:write("Magnification:1000",eol) + filehandle:write("Unit:1",eol) + filehandle:write("X Offset:0",eol) + filehandle:write("Y Offset:0",eol) + filehandle:write("Content:",eol) + flushpreamble = function() + writefiles() + return filehandle + end + else + enabled = false + end + return filehandle +end + +function synctex.wrapup() + if tmpfile then + renamefile(tmpfile,logfile) + end end local function flushpostamble() + if not filehandle then + return + end writeanchor() - f:write("Postamble:\n") - f:write("Count:"..nofobjects.."\n") + filehandle:write("Postamble:",eol) + filehandle:write("Count:",nofobjects,eol) writeanchor() - f:write("Post scriptum:\n") - f:close() + filehandle:write("Post scriptum:",eol) + filehandle:close() enabled = false end -local pageheight = 0 -- todo: set before we do this! +-- local function doaction(action,t,l,w,h,d) +-- local x, y = getpos() +-- filehandle:write(action(t,l,x,tex.pageheight-y,w,h,d)) +-- nofobjects = nofobjects + 1 +-- end +-- +-- local function noaction(action) +-- filehandle:write(action) +-- nofobjects = nofobjects + 1 +-- end +-- +-- local function b_vlist(head,current,t,l,w,h,d) +-- return insert_before(head,current,new_latelua(function() doaction(f_vlist,t,l,w,h,d) end)) +-- end +-- +-- local function b_hlist(head,current,t,l,w,h,d) +-- return insert_before(head,current,new_latelua(function() doaction(f_hlist,t,l,w,h,d) end)) +-- end +-- +-- local function e_vlist(head,current) +-- return insert_after(head,current,new_latelua(noaction(s_vlist))) +-- end +-- +-- local function e_hlist(head,current) +-- return insert_after(head,current,new_latelua(noaction(s_hlist))) +-- end +-- +-- local function x_vlist(head,current,t,l,w,h,d) +-- return insert_before(head,current,new_latelua(function() doaction(f_vlist_1,t,l,w,h,d) end)) +-- end +-- +-- local function x_hlist(head,current,t,l,w,h,d) +-- return insert_before(head,current,new_latelua(function() doaction(f_hlist_1,t,l,w,h,d) end)) +-- end +-- +-- generic +-- +-- local function doaction(t,l,w,h,d) +-- local x, y = getpos() +-- filehandle:write(f_hlist_1(t,l,x,tex.pageheight-y,w,h,d)) +-- nofobjects = nofobjects + 1 +-- end + +local x_hlist do -local function b_hlist(head,current,t,l,w,h,d) - return insert_before(head,current,new_latelua(function() + local function doaction_1(t,l,w,h,d) local x, y = getpos() - r = r + 1 - result[r] = f_hlist(t,l,x,tex.pageheight-y,w,h,d) + filehandle:write(f_hlist_1(t,l,x,tex.pageheight-y,w,h,d)) nofobjects = nofobjects + 1 - end)) -end + end -local function b_vlist(head,current,t,l,w,h,d) - return insert_before(head,current,new_latelua(function() + -- local lastx, lasty, lastw, lasth, lastd + -- + -- local function doaction_2(t,l,w,h,d) + -- local x, y = getpos() + -- y = tex.pageheight-y + -- filehandle:write(f_hlist_2(t,l, + -- x == lastx and "=" or x, + -- y == lasty and "=" or y, + -- w == lastw and "=" or w, + -- h == lasth and "=" or h, + -- d == lastd and "=" or d + -- )) + -- lastx, lasty, lastw, lasth, lastd = x, y, w, h, d + -- nofobjects = nofobjects + 1 + -- end + -- + -- but ... only y is supported: + + local lasty = false + + local function doaction_2(t,l,w,h,d) local x, y = getpos() - r = r + 1 - result[r] = f_vlist(t,l,x,tex.pageheight-y,w,h,d) + y = tex.pageheight - y + filehandle:write(f_hlist_2(t,l,x,y == lasty and "=" or y,w,h,d)) + lasty = y nofobjects = nofobjects + 1 - end)) -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 doaction = doaction_1 -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 + x_hlist = function(head,current,t,l,w,h,d) + return insert_before(head,current,new_latelua(function() doaction(t,l,w,h,d) 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 + directives.register("system.synctex.compression", function(v) + doaction = tonumber(v) == 2 and doaction_2 or doaction_1 + 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 +-- color is already handled so no colors --- 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 collect = nil +local fulltrace = false +local trace = false +local height = 10 * 65536 +local depth = 5 * 65536 +local traceheight = 32768 +local tracedepth = 32768 --- 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 +trackers.register("system.synctex.visualize", function(v) + trace = v + fulltrace = v == "real" +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 inject(head,first,last,tag,line) + local w, h, d = getdimensions(first,getnext(last)) + if h < height then + h = height + end + if d < depth then + d = depth + end + if trace then + head = insert_before(head,first,new_rule(w,fulltrace and h or traceheight,fulltrace and d or tracedepth)) + head = insert_before(head,first,new_kern(-w)) + end + head = x_hlist(head,first,tag,line,w,h,d) + return head +end -local function collect(head,t,l) +local function collect_min(head) local current = head while current do local id = getid(current) if id == glyph_code then local first = current local last = current + local tag = 0 + local line = 0 while true do - id = getid(current) - if id == glyph_code or id == disc_code then + if id == glyph_code then + local tc, lc = get_synctex_fields(current) + if tc and tc > 0 then + tag = tc + line = lc + end last = current - elseif id == kern_code and (getsubtype(current) == fontkern_code or getattr(current,a_fontkern)) then + elseif id == disc_code or (id == kern_code and getsubtype(current) == fontkern_code) 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))) + if tag > 0 then + head = inject(head,first,last,tag,line) 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))) + if current then + id = getid(current) + else + if tag > 0 then + head = inject(head,first,last,tag,line) 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 + -- pick up (as id can have changed) + if id == hlist_code or 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 + if list then + local l = collect(list) + if l ~= list then + setlist(current,l) 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 + current = getnext(current) + end + return head +end + +local function inject(parent,head,first,last,tag,line) + local w, h, d = getrangedimensions(parent,first,getnext(last)) + if h < height then + h = height + end + if d < depth then + d = depth + end + if trace then + head = insert_before(head,first,new_rule(w,fulltrace and h or traceheight,fulltrace and d or tracedepth)) + head = insert_before(head,first,new_kern(-w)) + end + head = x_hlist(head,first,tag,line,w,h,d) + return head +end + +local function collect_max(head,parent) + local current = head + while current do + local id = getid(current) + if id == glyph_code then + local first = current + local last = current + local tag = 0 + local line = 0 + while true do + if id == glyph_code then + local tc, lc = get_synctex_fields(current) + if tc and tc > 0 then + if tag > 0 and (tag ~= tc or line ~= lc) then + head = inject(parent,head,first,last,tag,line) + first = current end + tag = tc + line = lc + last = current + else + if tag > 0 then + head = inject(parent,head,first,last,tag,line) + tag = 0 + end + first = nil + last = nil 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) + elseif id == disc_code then + if not first then + first = current 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) + last = current + elseif id == kern_code and getsubtype(current) == fontkern_code then + if first then + last = current 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) + elseif id == glue_code then + if tag > 0 then + local tc, lc = get_synctex_fields(current) + if tc and tc > 0 then + if tag ~= tc or line ~= lc then + head = inject(parent,head,first,last,tag,line) + tag = 0 + break + end + else + head = inject(parent,head,first,last,tag,line) + tag = 0 + break end + else + tag = 0 + break 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) + id = nil -- so no test later on + elseif id == penalty_code then + -- go on (and be nice for math) + else + if tag > 0 then + head = inject(parent,head,first,last,tag,line) + tag = 0 end - head, current = e_vlist(head,current) + break + end + current = getnext(current) + if current then + id = getid(current) else - -- head = x_vlist(head,current,t,l,w,h,d) - head = x_vlist(head,current,0,0,w,h,d) + if tag > 0 then + head = inject(parent,head,first,last,tag,line) + end + return head end end - elseif id == glue_code then - local tc, lc = get_synctex_fields(current) - if tc > 0 then - t, l = tc, lc + end + -- pick up(as id can have changed) + if id == hlist_code or id == vlist_code then + local list = getlist(current) + if list then + local l = collect(list,current) + if l ~= list then + setlist(current,l) + end 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 +collect = collect_max -function synctex.collect(head) +function synctex.collect(head,where) if enabled then - result, r = { }, 0 - head = collect(tonut(head),0,0) - return tonode(head), true + if where == "object" then + return head, false + else + local h = tonut(head) + h = collect(h,h) + return tonode(h), true + end else return head, false end @@ -431,74 +638,159 @@ end -- also no solution for bad first file resolving in sumatra -function synctex.flush() +function synctex.start() 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) + if flushpreamble() then + writeanchor() + filehandle:write("{",nofsheets,eol) + -- this seems to work: + local h = tex.pageheight + local w = tex.pagewidth + filehandle:write(z_hlist) + filehandle:write(f_vlist_1(0,0,0,h,w,h,0)) end - f:write("\n") + end +end + +function synctex.stop() + if enabled then + filehandle:write(s_vlist,s_hlist) writeanchor() - f:write("}"..nofsheets.."\n") + filehandle:write("}",nofsheets,eol) nofobjects = nofobjects + 2 - result, r = { }, 0 end end +local enablers = { } +local disablers = { } + +function synctex.registerenabler(f) + enablers[#enablers+1] = f +end + +function synctex.registerdisabler(f) + disablers[#disablers+1] = f +end + function synctex.enable() - if not enabled and node.set_synctex_mode then + if not never and not enabled then enabled = true - node.set_synctex_mode(1) - tex.normalsynctex = 0 - nodes.tasks.appendaction("shipouts", "after", "nodes.synctex.collect") + set_synctex_mode(3) -- we want details + if not used then + nodes.tasks.appendaction("shipouts", "after", "luatex.synctex.collect") + report_system("synctex functionality is enabled, expect 5-10 pct runtime overhead!") + used = true + end + for i=1,#enablers do + enablers[i](true) + end + end +end + +function synctex.disable() + if enabled then + set_synctex_mode(0) + report_system("synctex functionality is disabled!") + enabled = false + for i=1,#disablers do + disablers[i](false) + end end end function synctex.finish() if enabled then flushpostamble() + else + makenames() + removefile(logfile) + removefile(tmpfile) end end +local filename = nil + +function synctex.pause() + paused = paused + 1 + if enabled and paused == 1 then + set_synctex_mode(0) + end +end + +function synctex.resume() + if enabled and paused == 1 then + set_synctex_mode(3) + end + paused = paused - 1 +end + -- not the best place luatex.registerstopactions(synctex.finish) -nodes.tasks.appendaction("shipouts", "after", "luatex.synctex.collect") - --- moved here +statistics.register("synctex tracing",function() + if used then + return string.format("%i referenced files, %i files ignored, %i objects flushed, logfile: %s", + noftags,nofblocked,nofobjects,logfile) + end +end) -local report_system = logs.reporter("system") -local synctex = false +local implement = interfaces.implement +local variables = interfaces.variables -directives.register("system.synctex", function(v) - if v == "context" then - luatex.synctex.enable() - setcount("normalsynctex",0) - synctex = true +function synctex.setup(t) + if t.state == variables.never then + synctex.disable() -- just in case + never = true + return + end + if t.method == variables.max then + collect = collect_max 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 + collect = collect_min end - if synctex then - report_system("synctex functionality is enabled (%s), expect runtime overhead!",tostring(v)) + if t.state == variables.start then + synctex.enable() else - report_system("synctex functionality is disabled!") + synctex.disable() end -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) +implement { + name = "synctexblockfilename", + arguments = "string", + actions = synctex.blockfilename, +} + +implement { + name = "synctexsetfilename", + arguments = "string", + actions = synctex.setfilename, +} + +implement { + name = "synctexresetfilename", + actions = synctex.resetfilename, +} + +implement { + name = "setupsynctex", + actions = synctex.setup, + arguments = { + { + { "state" }, + { "method" }, + }, + }, +} + +implement { + name = "synctexpause", + actions = synctex.pause, +} + +implement { + name = "synctexresume", + actions = synctex.resume, +} |