diff options
Diffstat (limited to 'tex/context/base/mkiv/node-syn.lua')
-rw-r--r-- | tex/context/base/mkiv/node-syn.lua | 706 |
1 files changed, 340 insertions, 366 deletions
diff --git a/tex/context/base/mkiv/node-syn.lua b/tex/context/base/mkiv/node-syn.lua index 2fdea49c1..bd8cc7964 100644 --- a/tex/context/base/mkiv/node-syn.lua +++ b/tex/context/base/mkiv/node-syn.lua @@ -6,33 +6,51 @@ 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 synctex, 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. - --- InverseSearchCmdLine = mtxrun.exe --script synctex --edit --name="%f" --line="%l" $ - --- Unfortunately syntex always removes the files at the end and not at the start (it --- happens in synctexterminate). This forces us to use an intermediate file, no big deal --- in context (which has a runner) but definitely not nice. +-- 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. local type, rawset = type, rawset local concat = table.concat local formatters = string.formatters -local replacesuffix = file.replacesuffix - -local trace = false trackers.register("system.synctex.visualize", function(v) trace = v end) +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 tex = tex + local nuts = nodes.nuts local tonut = nuts.tonut local tonode = nuts.tonode @@ -48,14 +66,13 @@ local getsubtype = nuts.getsubtype local nodecodes = nodes.nodecodes local kerncodes = nodes.kerncodes +local glyph_code = nodecodes.glyph +local disc_code = nodecodes.disc local glue_code = nodecodes.glue 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 @@ -77,36 +94,31 @@ 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 getcount = tex.getcount -local setcount = tex.setcount +local set_synctex_mode = tex.set_synctex_mode local getpos = function() getpos = backends.codeinjections.getpos return getpos() end +local foundintree = resolvers.foundintree local eol = "\010" -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 foundintree = resolvers.foundintree -local suffixonly = file.suffix -local nameonly = file.nameonly - -local synctex = { } +----- 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_hlist = formatters["[%i,%i:%i,%i:%i,%i,%i\010"] +----- f_vlist = formatters["(%i,%i:%i,%i:%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" +local s_hlist = "]\010" +local s_vlist = ")\010" +local f_hvoid = formatters["h%i,%i:%i,%i:%i,%i,%i\010"] +----- f_vvoid = formatters["v%i,%i:%i,%i:%i,%i,%i\010"] + +local synctex = luatex.synctex or { } luatex.synctex = synctex -- the file name stuff @@ -168,22 +180,19 @@ end -- the node stuff -local result = { } -local r = 0 -local f = nil +local filehandle = nil local nofsheets = 0 local nofobjects = 0 local last = 0 local filesdone = 0 local enabled = false -local compact = true -local fulltrace = false +local tmpfile = false local logfile = false local used = false local function writeanchor() - local size = f:seek("end") - f:write("!" .. (size-last) ..eol) + local size = filehandle:seek("end") + filehandle:write("!",size-last,eol) last = size end @@ -191,310 +200,295 @@ local function writefiles() local total = #stnums if filesdone < total then for i=filesdone+1,total do - f:write("Input:"..i..":"..stnums[i]..eol) + 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() - logfile = replacesuffix(tex.jobname,"syncctx") - f = io.open(logfile,"wb") - f:write("SyncTeX Version:1"..eol) - writefiles() - f:write("Output:pdf"..eol) - f:write("Magnification:1000"..eol) - f:write("Unit:1"..eol) - f:write("X Offset:0"..eol) - f:write("Y Offset:0"..eol) - f:write("Content:"..eol) - 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 logfile then - os.rename(logfile,replacesuffix(logfile,"synctex")) + if tmpfile then + renamefile(tmpfile,logfile) end end local function flushpostamble() - if not f then + if not filehandle then return end writeanchor() - f:write("Postamble:"..eol) - f:write("Count:"..nofobjects..eol) + filehandle:write("Postamble:",eol) + filehandle:write("Count:",nofobjects,eol) writeanchor() - f:write("Post scriptum:"..eol) - f:close() + filehandle:write("Post scriptum:",eol) + filehandle: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)) +-- 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 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)) +-- +-- local function noaction(action) +-- filehandle:write(action) +-- nofobjects = nofobjects + 1 -- 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)) +-- +-- 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 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)) +-- +-- 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_vvoid,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_hvoid,t,l,w,h,d) end)) +-- end + +local function doaction(t,l,w,h,d) + local x, y = getpos() + filehandle:write(f_hvoid(t,l,x,tex.pageheight-y,w,h,d)) + nofobjects = nofobjects + 1 +end --- todo: why not only lines --- todo: larger ranges +local function x_hlist(head,current,t,l,w,h,d) + return insert_before(head,current,new_latelua(function() doaction(t,l,w,h,d) end)) +end -- color is already handled so no colors --- we can have ranges .. more efficient but a bit more complex to analyze ... some day +local collect = nil +local fulltrace = false +local trace = false +local height = 10 * 65536 +local depth = 5 * 65536 +local traceheight = 32768 +local tracedepth = 32768 + +trackers.register("system.synctex.visualize", function(v) + trace = v + fulltrace = v == "real" +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_hlist(new_rule(w,fulltrace and h or traceheight,fulltrace and d or tracedepth))) + end + head = x_hlist(head,first,tag,line,w,h,d) + return head +end -local function collect(head,t,l,dp,ht) +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) - -- traditionally glyphs have no synctex code which works sort of ok - -- but not when we don't leave hmode cq. have no par - -- - 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 - t, l = tc, lc + tag = tc + line = lc end last = current - elseif id == kern_code and getsubtype(current) == fontkern_code then - local tc, lc = get_synctex_fields(current) - if tc and tc > 0 then - t, l = tc, lc - end + 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 dp and d < dp then d = dp end - if ht and h < ht then h = ht end - if h < 655360 then h = 655360 end - if d < 327680 then d = 327680 end - if trace then - head = insert_before(head,first,new_hlist(new_rule(w,fulltrace and h or 32768,fulltrace and d or 32768))) + if tag > 0 then + head = inject(head,first,last,tag,line) 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 dp and d < dp then d = dp end - if ht and h < ht then h = ht end - if h < 655360 then h = 655360 end - if d < 327680 then d = 327680 end - if trace then - head = insert_before(head,first,new_hlist(new_rule(w,fulltrace and h or 32768,fulltrace and d or 32768))) + if current then + id = getid(current) + else + if tag > 0 then + head = inject(head,first,last,tag,line) 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 + +collect = collect_max + +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_hlist(new_rule(w,fulltrace and h or traceheight,fulltrace and d or tracedepth))) + 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) -- todo: only d h when line - local l = collect(list,t,l,d,h) - 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) -- todo: only d h when line - 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 + 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 - function synctex.collect(head) if enabled then - result, r = { }, 0 - head = collect(tonut(head),0,0) - return tonode(head), true + local h = tonut(head) + h = collect(h,h) + return tonode(h), true else return head, false end @@ -502,106 +496,73 @@ 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..eol) - if compact then - -- f:write(f_vlist(0,0,0,0,tex.pagewidth,tex.pageheight,0)) - f:write(f_hlist(0,0,0,0,0,0,0)) - f:write(eol) - f:write(f_vlist(0,0,0,0,0,0,0)) - f:write(eol) + if flushpreamble() then + writeanchor() + filehandle:write("{",nofsheets,eol) + filehandle:write(z_hlist,z_vlist) end - f:write(concat(result,eol)) - if compact then - f:write(eol) - f:write(s_vlist) - f:write(eol) - f:write(s_hlist) - end - f:write(eol) + end +end + +function synctex.stop() + if enabled then + filehandle:write(s_vlist,s_hlist) writeanchor() - f:write("}"..nofsheets..eol) + filehandle:write("}",nofsheets,eol) nofobjects = nofobjects + 2 - result, r = { }, 0 end end -local details = 1 -local state = 0 - -directives.register("system.synctex.details",function(v) - details = tonumber(v) or 1 -end) - -local set_synctex_mode = tex.set_synctex_mode - -if set_synctex_mode then - - function synctex.enable() - if not enabled then - enabled = true - state = details or 1 - set_synctex_mode(state) - if not used then - directives.enable("system.synctex.xml") - nodes.tasks.appendaction("shipouts", "after", "nodes.synctex.collect") - report_system("synctex functionality is enabled, expect runtime overhead!") - used = true - end - elseif state > 0 then - set_synctex_mode(state) +function synctex.enable() + if not enabled then + enabled = true + set_synctex_mode(3) -- we want details + if not used then + directives.enable("system.synctex.xml") + nodes.tasks.appendaction("shipouts", "after", "luatex.synctex.collect") + report_system("synctex functionality is enabled, expect 5-10 pct runtime overhead!") + used = true end end +end - function synctex.disable() - if enabled then - set_synctex_mode(0) - report_system("synctex functionality is disabled!") - enabled = false - end +function synctex.disable() + if enabled then + set_synctex_mode(0) + report_system("synctex functionality is disabled!") + enabled = false end +end - function synctex.finish() - if enabled then - flushpostamble() - else - os.remove(replacesuffix(tex.jobname,"syncctx")) - os.remove(replacesuffix(tex.jobname,"synctex")) - end +function synctex.finish() + if enabled then + flushpostamble() + else + makenames() + removefile(logfile) + removefile(tmpfile) end +end - function synctex.pause() - if enabled then - set_synctex_mode(0) - end +function synctex.pause() + if enabled then + set_synctex_mode(0) end +end - function synctex.resume() - if enabled then - set_synctex_mode(state) - end +function synctex.resume() + if enabled then + set_synctex_mode(3) end - -else - - function synctex.enable () end - function synctex.disable() end - function synctex.finish () end - function synctex.pause () end - function synctex.resume () end - end -- not the best place luatex.registerstopactions(synctex.finish) -nodes.tasks.appendaction("shipouts", "after", "luatex.synctex.collect") - directives.register("system.synctex", function(v) if v then synctex.enable() @@ -612,7 +573,8 @@ end) statistics.register("synctex tracing",function() if used then - return string.format("%i referenced files, %i files ignored, logfile: %s",noftags,nofblocked,logfile) + return string.format("%i referenced files, %i files ignored, %i objects flushed, logfile: %s", + noftags,nofblocked,nofobjects,logfile) end end) @@ -634,13 +596,25 @@ interfaces.implement { } interfaces.implement { - name = "synctexenable", - actions = synctex.enable, -} - -interfaces.implement { - name = "synctexdisable", - actions = synctex.disable, + name = "setupsynctex", + arguments = { + { + { "state" }, + { "method" }, + }, + }, + actions = function(t) + if t.method == interfaces.variables.max then + collect = collect_max + else + collect = collect_min + end + if t.state == interfaces.variables.start then + synctex.enable() + else + synctex.disable() + end + end } interfaces.implement { |