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.lua922
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,
+}