diff options
Diffstat (limited to 'Master/texmf-dist/tex/context/base/mkiv/mlib-run.lua')
-rw-r--r-- | Master/texmf-dist/tex/context/base/mkiv/mlib-run.lua | 570 |
1 files changed, 374 insertions, 196 deletions
diff --git a/Master/texmf-dist/tex/context/base/mkiv/mlib-run.lua b/Master/texmf-dist/tex/context/base/mkiv/mlib-run.lua index 09872ef0fb7..07fa6a19198 100644 --- a/Master/texmf-dist/tex/context/base/mkiv/mlib-run.lua +++ b/Master/texmf-dist/tex/context/base/mkiv/mlib-run.lua @@ -6,8 +6,6 @@ if not modules then modules = { } end modules ['mlib-run'] = { license = "see context related readme files", } --- todo mpx :execute -> mlib.execute(mpx,) - -- cmyk -> done, native -- spot -> done, but needs reworking (simpler) -- multitone -> @@ -32,7 +30,7 @@ nears zero.</p> --ldx]]-- local type, tostring, tonumber, next = type, tostring, tonumber, next -local striplines = utilities.strings.striplines +local find, striplines = string.find, utilities.strings.striplines local concat, insert, remove = table.concat, table.insert, table.remove local emptystring = string.is_empty @@ -40,8 +38,10 @@ local P = lpeg.P local trace_graphics = false trackers.register("metapost.graphics", function(v) trace_graphics = v end) local trace_tracingall = false trackers.register("metapost.tracingall", function(v) trace_tracingall = v end) +local trace_terminal = false trackers.register("metapost.terminal", function(v) trace_terminal = v end) local report_metapost = logs.reporter("metapost") +local report_terminal = logs.reporter("metapost","terminal") local texerrormessage = logs.texerrormessage local starttiming = statistics.starttiming @@ -55,11 +55,55 @@ local metapost = metapost metapost.showlog = false metapost.lastlog = "" -metapost.collapse = true -- currently mplib cannot deal with begingroup/endgroup mismatch in stepwise processing metapost.texerrors = false metapost.exectime = metapost.exectime or { } -- hack +metapost.nofruns = 0 + +local mpxformats = { } +local mpxterminals = { } +local nofformats = 0 +local mpxpreambles = { } +local mpxextradata = { } + +-- The flatten hack is needed because the library currently barks on \n\n and the +-- collapse because mp cannot handle snippets due to grouping issues. + +-- todo: pass tables to executempx instead of preparing beforehand, +-- as it's more efficient for the terminal + +local function flatten(source,target) + for i=1,#source do + local d = source[i] + if type(d) == "table" then + flatten(d,target) + elseif d and d ~= "" then + target[#target+1] = d + end + end + return target +end + +local function prepareddata(data) + if data and data ~= "" then + if type(data) == "table" then + data = flatten(data,{ }) + data = #data > 1 and concat(data,"\n") or data[1] + end + return data + end +end --- metapost.collapse = false +local function executempx(mpx,data) + local terminal = mpxterminals[mpx] + if terminal then + terminal.writer(data) + data = "" + elseif type(data) == "table" then + data = prepareddata(data,collapse) + end + metapost.nofruns = metapost.nofruns + 1 + return mpx:execute(data) +end directives.register("mplib.texerrors", function(v) metapost.texerrors = v end) trackers.register ("metapost.showlog", function(v) metapost.showlog = v end) @@ -77,7 +121,7 @@ local mpbasepath = lpeg.instringchecker(P("/metapost/") * (P("context") + P("bas -- for some reason mp sometimes calls this function twice which is inefficient -- but we cannot catch this -do +local realtimelogging do local finders = { } mplib.finders = finders -- also used in meta-lua.lua @@ -85,12 +129,10 @@ do local new_instance = mplib.new local function validftype(ftype) - if ftype == "" then - -- whatever - elseif ftype == 0 then - -- mplib bug + if ftype == "mp" then + return "mp" else - return ftype + return nil end end @@ -98,6 +140,8 @@ do return resolvers.findfile(name,validftype(ftype)) end + -- this will be redone in lmtx + local function i_finder(name,mode,ftype) -- fake message for mpost.map and metafun.mpvi local specification = url.hashed(name) local finder = finders[specification.scheme] or finders.file @@ -115,9 +159,172 @@ do return (mode == "w" and o_finder or i_finder)(name,mode,validftype(ftype)) end - function mplib.new(specification) - specification.find_file = finder -- so we block an overload - return new_instance(specification) + local report_logger = logs.reporter("metapost log") + local report_error = logs.reporter("metapost error") + + local l, nl, dl = { }, 0, false + local t, nt, dt = { }, 0, false + local e, ne, de = { }, 0, false + + local function logger(target,str) + if target == 1 then + -- log + elseif target == 2 or target == 3 then + -- term + if str == "\n" then + realtimelogging = true + if nl > 0 then + report_logger(concat(l,"",1,nl)) + nl, dl = 0, false + elseif not dl then + report_logger("") + dl = true + end + else + nl = nl + 1 + l[nl] = str + end + elseif target == 4 then + report_error(str) + end + end + + -- experiment, todo: per instance, just a push / pop ? + + local findtexfile = resolvers.findtexfile + local opentexfile = resolvers.opentexfile + local splitlines = string.splitlines + + local function writetoterminal(terminaldata,maxterm,d) + local t = type(d) + local n = 0 + if t == "string" then + d = splitlines(d) + n = #d + for i=1,#d do + maxterm = maxterm + 1 + terminaldata[maxterm] = d[i] + end + elseif t == "table" then + for i=1,#d do + local l = d[i] + if find(l,"[\n\r]") then + local s = splitlines(l) + local m = #s + for i=1,m do + maxterm = maxterm + 1 + terminaldata[maxterm] = s[i] + end + n = n + m + else + maxterm = maxterm + 1 + terminaldata[maxterm] = d[i] + n = 1 + end + end + end + if trace_terminal then + report_metapost("writing %i lines, in cache %s",n,maxterm) + end + return maxterm + end + + local function readfromterminal(terminaldata,maxterm,nowterm) + if nowterm >= maxterm then + terminaldata[nowterm] = false + maxterm = 0 + nowterm = 0 + if trace_terminal then + report_metapost("resetting, maxcache %i",#terminaldata) + end + return maxterm, nowterm, nil + else + if nowterm > 0 then + terminaldata[nowterm] = false + end + nowterm = nowterm + 1 + local s = terminaldata[nowterm] + if trace_terminal then + report_metapost("reading line %i: %s",nowterm,s) + end + return maxterm, nowterm, s + end + end + + local function fileopener() + + -- these can go into the table itself + + local terminaldata = { } + local maxterm = 0 + local nowterm = 0 + + local terminal = { + name = "terminal", + close = function() + -- terminal = { } + -- maxterm = 0 + -- nowterm = 0 + end, + reader = function() + local line + maxterm, nowterm, line = readfromterminal(terminaldata,maxterm,nowterm) + return line + end, + writer = function(d) + maxterm = writetoterminal(terminaldata,maxterm,d) + end, + } + + return function(name,mode,kind) + if name == "terminal" then + -- report_metapost("opening terminal") + return terminal + elseif mode == "w" then + local f = io.open(name,"wb") + if f then + -- report_metapost("opening file %a for writing",full) + return { + name = full, + writer = function(s) return f:write(s) end, -- io.write(f,s) + close = function() f:close() end, + } + end + else + local full = findtexfile(name,validftype(ftype)) + if full then + -- report_metapost("opening file %a for reading",full) + return opentexfile(full) + end + end + end + + end + + -- end of experiment + + if CONTEXTLMTXMODE > 0 then + + function mplib.new(specification) + local openfile = fileopener() + specification.find_file = finder + specification.run_logger = logger + specification.open_file = openfile + specification.interaction = "silent" + specification.halt_on_error = true + local instance = new_instance(specification) + mpxterminals[instance] = openfile("terminal") + return instance + end + + else + + function mplib.new(specification) + specification.find_file = finder + specification.run_logger = logger + return new_instance(specification) + end + end mplib.finder = finder @@ -130,7 +337,12 @@ local find_file = mplib.finder function metapost.reporterror(result) if not result then report_metapost("error: no result object returned") - elseif result.status > 0 then + return true + elseif result.status == 0 then + return false + elseif realtimelogging then + return false -- we already reported + else local t = result.term local e = result.error local l = result.log @@ -150,10 +362,8 @@ function metapost.reporterror(result) else report_metapost("error: unknown, no error, terminal or log messages") end - else - return false + return true end - return true end local f_preamble = formatters [ [[ @@ -173,7 +383,7 @@ local methods = { } function metapost.runscript(code) - return code + return "" end function metapost.scripterror(str) @@ -203,13 +413,17 @@ function metapost.load(name,method) make_text = metapost.maketext, extensions = 1, -- random_seed = seed, + utf8_mode = true, } report_metapost("initializing number mode %a",method) local result if not mpx then result = { status = 99, error = "out of memory"} else - result = mpx:execute(f_preamble(file.addsuffix(name,"mp"),seed)) -- addsuffix is redundant + -- pushing permits advanced features + metapost.pushscriptrunner(mpx) + result = executempx(mpx,f_preamble(file.addsuffix(name,"mp"),seed)) + metapost.popscriptrunner() end stoptiming(mplib) metapost.reporterror(result) @@ -222,8 +436,11 @@ function metapost.checkformat(mpsinput,method) if file.suffix(mpsinput) ~= "" then foundfile = find_file(mpsinput) or "" end - if foundfile == "" then - foundfile = find_file(file.replacesuffix(mpsinput,"mpvi")) or "" + -- if foundfile == "" then + -- foundfile = find_file(file.replacesuffix(mpsinput,"mpvi")) or "" + -- end + if CONTEXTLMTXMODE > 0 and foundfile == "" then + foundfile = find_file(file.replacesuffix(mpsinput,"mpxl")) or "" end if foundfile == "" then foundfile = find_file(file.replacesuffix(mpsinput,"mpiv")) or "" @@ -253,40 +470,13 @@ function metapost.unload(mpx) stoptiming(mplib) end --- The flatten hack is needed because the library currently barks on \n\n and the --- collapse because mp cannot handle snippets due to grouping issues. - -local function flatten(source,target) - for i=1,#source do - local d = source[i] - if type(d) == "table" then - flatten(d,target) - elseif d and d ~= "" then - target[#target+1] = d - end - end - return target -end - -local function prepareddata(data,collapse) - if data and data ~= "" then - if type(data) == "table" then - data = flatten(data,{ }) - if collapse then - data = #data > 1 and concat(data,"\n") or data[1] - end - end - return data - end -end - metapost.defaultformat = "metafun" metapost.defaultinstance = "metafun" metapost.defaultmethod = "default" -local mpxformats = { } -local nofformats = 0 -local mpxpreambles = { } +function metapost.getextradata(mpx) + return mpxextradata[mpx] +end function metapost.pushformat(specification,f,m) -- was: instance, name, method if type(specification) ~= "table" then @@ -326,29 +516,30 @@ function metapost.pushformat(specification,f,m) -- was: instance, name, method end nofformats = nofformats + 1 local usedinstance = instance .. ":" .. nofformats - local mpx = mpxformats[usedinstance] + local mpx = mpxformats [usedinstance] local mpp = mpxpreambles[instance] or "" + -- report_metapost("push instance %a (%S)",usedinstance,mpx) if preamble then - preamble = prepareddata(preamble,true) + preamble = prepareddata(preamble) mpp = mpp .. "\n" .. preamble mpxpreambles[instance] = mpp end if not mpx then report_metapost("initializing instance %a using format %a and method %a",usedinstance,format,method) mpx = metapost.checkformat(format,method) - mpxformats[usedinstance] = mpx + mpxformats [usedinstance] = mpx + mpxextradata[mpx] = { } if mpp ~= "" then preamble = mpp end end if preamble then - mpx:execute(preamble) + executempx(mpx,preamble) end specification.mpx = mpx return mpx end - -- luatex.wrapup(function() -- for k, mpx in next, mpxformats do -- mpx:finish() @@ -364,14 +555,19 @@ function metapost.reset(mpx) -- nothing elseif type(mpx) == "string" then if mpxformats[mpx] then - mpxformats[mpx]:finish() - mpxformats[mpx] = nil + local instance = mpxformats[mpx] + instance:finish() + mpxterminals[instance] = nil + mpxextradata[mpx] = nil + mpxformats [mpx] = nil end else for name, instance in next, mpxformats do if instance == mpx then mpx:finish() - mpxformats[name] = nil + mpxextradata[mpx] = nil + mpxformats [mpx] = nil + mpxterminals[mpx] = nil break end end @@ -461,7 +657,7 @@ function metapost.run(specification) end if mpx and data then local tra = nil - starttiming(metapost) + starttiming(metapost) -- why not at the outer level ... metapost.variables = { } -- todo also push / pop metapost.pushscriptrunner(mpx) if trace_graphics then @@ -479,20 +675,25 @@ function metapost.run(specification) tra.inp:write(banner) tra.log:write(banner) end - local data = prepareddata(data,metapost.collapse) local function process(d,i) if d then if trace_graphics then if i then tra.inp:write(formatters["\n%% begin snippet %s\n"](i)) end - tra.inp:write(d) + if type(d) == "table" then + for i=1,#d do + tra.inp:write(d[i]) + end + else + tra.inp:write(d) + end if i then tra.inp:write(formatters["\n%% end snippet %s\n"](i)) end end starttiming(metapost.exectime) - result = mpx:execute(d) + result = executempx(mpx,d) stoptiming(metapost.exectime) if trace_graphics and result then local str = result.log or result.error @@ -502,6 +703,7 @@ function metapost.run(specification) end if not metapost.reporterror(result) then if metapost.showlog then + -- make function and overload in lmtx local str = result.term ~= "" and result.term or "no terminal output" if not emptystring(str) then metapost.lastlog = metapost.lastlog .. "\n" .. str @@ -519,14 +721,16 @@ function metapost.run(specification) end end +-- local data = prepareddata(data) if type(data) == "table" then if trace_tracingall then - mpx:execute("tracingall;") + executempx(mpx,"tracingall;") end - for i=1,#data do - process(data[i],i) - end - else + process(data) +-- for i=1,#data do +-- process(data[i],i) +-- end + else if trace_tracingall then data = "tracingall;" .. data end @@ -554,125 +758,71 @@ if not metapost.convert then end --- handy +-- This will be redone as we no longer output svg of ps! -function metapost.directrun(formatname,filename,outputformat,astable,mpdata) - local fullname = file.addsuffix(filename,"mp") - local data = mpdata or io.loaddata(fullname) - if outputformat ~= "svg" then - outputformat = "mps" - end - if not data then - report_metapost("unknown file %a",filename) - else - local mpx = metapost.checkformat(formatname) - if not mpx then - report_metapost("unknown format %a",formatname) - else - report_metapost("processing %a",(mpdata and (filename or "data")) or fullname) - local result = mpx:execute(data) - if not result then - report_metapost("error: no result object returned") - elseif result.status > 0 then - report_metapost("error: %s",(result.term or "no-term") .. "\n" .. (result.error or "no-error")) - else - if metapost.showlog then - metapost.lastlog = metapost.lastlog .. "\n" .. result.term - report_metapost("info: %s",result.term or "no-term") - end - local figures = result.fig - if figures then - local sorted = table.sortedkeys(figures) - if astable then - local result = { } - report_metapost("storing %s figures in table",#sorted) - for k=1,#sorted do - local v = sorted[k] - if outputformat == "mps" then - result[v] = figures[v]:postscript() - else - result[v] = figures[v]:svg() -- (3) for prologues - end - end - return result - else - local basename = file.removesuffix(file.basename(filename)) - for k=1,#sorted do - local v = sorted[k] - local output - if outputformat == "mps" then - output = figures[v]:postscript() - else - output = figures[v]:svg() -- (3) for prologues - end - local outname = formatters["%s-%s.%s"](basename,v,outputformat) - report_metapost("saving %s bytes in %a",#output,outname) - io.savedata(outname,output) - end - return #sorted - end - end - end - end - end -end - --- goodie - -function metapost.quickanddirty(mpxformat,data,incontext) - if not data then - mpxformat = "metafun" - data = mpxformat - end - local code, bbox - local flusher = { - startfigure = function(n,llx,lly,urx,ury) - code = { } - bbox = { llx, lly, urx, ury } - end, - flushfigure = function(t) - for i=1,#t do - code[#code+1] = t[i] - end - end, - stopfigure = function() - end - } - local data = formatters["; beginfig(1) ;\n %s\n ; endfig ;"](data) - metapost.process { - mpx = mpxformat, - flusher = flusher, - askedfig = "all", - useplugins = incontext, - incontext = incontext, - data = { data }, - } - if code then - return { - bbox = bbox or { 0, 0, 0, 0 }, - code = code, - data = data, - } - else - report_metapost("invalid quick and dirty run") - end -end +-- function metapost.directrun(formatname,filename,outputformat,astable,mpdata) +-- local fullname = file.addsuffix(filename,"mp") +-- local data = mpdata or io.loaddata(fullname) +-- if outputformat ~= "svg" then +-- outputformat = "mps" +-- end +-- if not data then +-- report_metapost("unknown file %a",filename) +-- else +-- local mpx = metapost.checkformat(formatname) +-- if not mpx then +-- report_metapost("unknown format %a",formatname) +-- else +-- report_metapost("processing %a",(mpdata and (filename or "data")) or fullname) +-- local result = executempx(mpx,data) +-- if not result then +-- report_metapost("error: no result object returned") +-- elseif result.status > 0 then +-- report_metapost("error: %s",(result.term or "no-term") .. "\n" .. (result.error or "no-error")) +-- else +-- if metapost.showlog then +-- metapost.lastlog = metapost.lastlog .. "\n" .. result.term +-- report_metapost("info: %s",result.term or "no-term") +-- end +-- local figures = result.fig +-- if figures then +-- local sorted = table.sortedkeys(figures) +-- if astable then +-- local result = { } +-- report_metapost("storing %s figures in table",#sorted) +-- for k=1,#sorted do +-- local v = sorted[k] +-- if outputformat == "mps" then +-- result[v] = figures[v]:postscript() +-- else +-- result[v] = figures[v]:svg() -- (3) for prologues +-- end +-- end +-- return result +-- else +-- local basename = file.removesuffix(file.basename(filename)) +-- for k=1,#sorted do +-- local v = sorted[k] +-- local output +-- if outputformat == "mps" then +-- output = figures[v]:postscript() +-- else +-- output = figures[v]:svg() -- (3) for prologues +-- end +-- local outname = formatters["%s-%s.%s"](basename,v,outputformat) +-- report_metapost("saving %s bytes in %a",#output,outname) +-- io.savedata(outname,output) +-- end +-- return #sorted +-- end +-- end +-- end +-- end +-- end +-- end -function metapost.getstatistics(memonly) - if memonly then - local n, m = 0, 0 - for name, mpx in next, mpxformats do - n = n + 1 - m = m + mpx:statistics().memory - end - return n, m - else - local t = { } - for name, mpx in next, mpxformats do - t[name] = mpx:statistics() - end - return t - end +function metapost.directrun(formatname,filename,outputformat,astable,mpdata) + report_metapost("producing postscript and svg is no longer supported") end do @@ -681,6 +831,7 @@ do local width = 0 local height = 0 local depth = 0 + local bbox = { 0, 0, 0, 0 } local flusher = { startfigure = function(n,llx,lly,urx,ury) @@ -688,35 +839,62 @@ do width = urx - llx height = ury depth = -lly + bbox = { llx, lly, urx, ury } end, flushfigure = function(t) + local r = #result for i=1,#t do - result[#result+1] = t[i] + r = r + 1 + result[r] = t[i] end end, stopfigure = function() - end + end, } - function metapost.simple(format,code) -- even less than metapost.quickcanddirty - local mpx = metapost.pushformat { } -- takes defaults - -- metapost.setoutercolor(2) + -- make table variant: + + function metapost.simple(instance,code,useextensions,dontwrap) + -- can we pickup the instance ? + local mpx = metapost.pushformat { + instance = instance or "simplefun", + format = "metafun", -- or: minifun + method = "double", + } metapost.process { mpx = mpx, flusher = flusher, askedfig = 1, - useplugins = false, + useplugins = useextensions, + data = dontwrap and { code } or { "beginfig(1);", code, "endfig;" }, incontext = false, - data = { "beginfig(1);", code, "endfig;" }, } metapost.popformat() if result then local stream = concat(result," ") - result = nil -- cleanup - return stream, width, height, depth + result = { } -- nil -- cleanup .. weird, we can have a dangling q + return stream, width, height, depth, bbox else - return "", 0, 0, 0 + return "", 0, 0, 0, { 0, 0, 0, 0 } end end end + +function metapost.getstatistics(memonly) + if memonly then + local n, m = 0, 0 + for name, mpx in next, mpxformats do + n = n + 1 + m = m + mpx:statistics().memory + end + return n, m + else + local t = { } + for name, mpx in next, mpxformats do + t[name] = mpx:statistics() + end + return t + end +end + |