summaryrefslogtreecommitdiff
path: root/macros/luatex/generic/minim-mp/minim-mp.lua
diff options
context:
space:
mode:
Diffstat (limited to 'macros/luatex/generic/minim-mp/minim-mp.lua')
-rw-r--r--macros/luatex/generic/minim-mp/minim-mp.lua213
1 files changed, 154 insertions, 59 deletions
diff --git a/macros/luatex/generic/minim-mp/minim-mp.lua b/macros/luatex/generic/minim-mp/minim-mp.lua
index fba6573239..885a6941e4 100644
--- a/macros/luatex/generic/minim-mp/minim-mp.lua
+++ b/macros/luatex/generic/minim-mp/minim-mp.lua
@@ -102,6 +102,14 @@ function M.enable_debugging()
end
E.enable_debugging = M.enable_debugging
+alloc.luadef('debugmetapost', M.enable_debugging)
+
+local function debug(...)
+ if debugging then
+ alloc.log(...)
+ end
+end
+
local function print_prop(append, obj, prop)
if obj[prop] then
local val = string.gsub(tostring(obj[prop]), '\r', '<CR>')
@@ -136,9 +144,8 @@ local function print_knots(append, obj, ptype)
end
function A.printobj(append, obj)
- if not debugging then return end
local nc = append.node_count
- append:literal('%%Object Type: %s', obj.type)
+ append:literal('%% Object Type: %s', obj.type)
print_prop(append, obj, 'text')
print_prop(append, obj, 'font')
print_prop(append, obj, 'dsize')
@@ -151,16 +158,16 @@ function A.printobj(append, obj)
print_knots(append, obj, 'htap')
if obj.pen then
local x = obj.pen.type or 'not elliptical'
- append:literal('%% pen: see below, form: %s', x)
+ append:literal('%% pen is %s', x)
x = mplib.pen_info(obj)
- append:literal('%% | width: %s', tostring(x.width))
- append:literal('%% | sx: %s', tostring(x.sx))
- append:literal('%% | sy: %s', tostring(x.sy))
- append:literal('%% | rx: %s', tostring(x.rx))
- append:literal('%% | ry: %s', tostring(x.ry))
- append:literal('%% | tx: %s', tostring(x.tx))
- append:literal('%% | ty: %s', tostring(x.ty))
- print_knots(append, obj, 'pen')
+ append:literal('%% width: %s', tostring(x.width))
+ append:literal('%% sx: %s', tostring(x.sx))
+ append:literal('%% sy: %s', tostring(x.sy))
+ append:literal('%% rx: %s', tostring(x.rx))
+ append:literal('%% ry: %s', tostring(x.ry))
+ append:literal('%% tx: %s', tostring(x.tx))
+ append:literal('%% ty: %s', tostring(x.ty))
+ print_knots(append, obj, 'pen path')
end
if obj.dash then
local d = ''
@@ -420,7 +427,9 @@ function A.linestate (append, object)
append.dashed = false
table.insert(res, '[] 0 d')
end
- append:literal(table.concat(res, ' '))
+ if #res > 0 then
+ append:literal(table.concat(res, ' '))
+ end
end
-- 2 path literals
@@ -482,7 +491,7 @@ function A.curve(append, path, open, concat)
elseif #path == 1 then
append_line(path[1], 'l') -- special case: draw a point
end
- append:literal(table.concat(res, ' '))
+ append:literal(table.concat(res, '\n'))
end
-- And actually draw the path.
@@ -556,7 +565,9 @@ end
local function parse_object(append, object)
append.object_info = { }
- append:printobj(object)
+ if debugging then
+ append:printobj(object)
+ end
local processor = nil
for sp, instr in split_specials(object.prescript) do
if not sp then
@@ -1018,8 +1029,8 @@ M.instances = instances
-- parameters: wd, ht+dp, dp
local function make_transform(w, h, d)
- return string.format('identity xscaled %fpt yscaled %fpt shifted (0,-%fpt)',
- w/65536, (h+d)/65536, d/65536)
+ return string.format('identity xscaled %fpt yscaled %fpt shifted (0,%fpt)',
+ w/65536, (h+d)/65536, -d/65536)
end
local status_names = { [0] = 'good', 'warning', 'error', 'fatal' }
@@ -1028,16 +1039,19 @@ local function print_status(st)
end
M.on_line = false
+M.max_errprint = 1
local function print_log (nr, res, why)
local i = instances[nr]
-- only write to term if on_line or if exit status increases
- local log, alog
+ local log, alog --luacheck:ignore 231
if M.on_line or res.status > i.status then
- local nrlines, maxlines = 0, 16
alog = alloc.amsg
+ local nr_errs = 0
log = function(...)
- if M.on_line or nrlines < maxlines then
- nrlines = nrlines + 1
+ if string.sub(table.pack(...)[2],1,2) == "! " then
+ nr_errs = nr_errs + 1
+ end
+ if M.max_errprint < 1 or M.max_errprint >= nr_errs then
alloc.msg(...)
else
alloc.log(...)
@@ -1050,17 +1064,18 @@ local function print_log (nr, res, why)
end
-- split log into lines; discard empty lines at the end
local report = res.log and res.log:explode('\n') or { }
- while report[#report] == '' do
- report[#report] = nil
- end
-- write out the log
- log('┌ %smetapost instance %s (%d)', why or '', i.jobname, i.nr)
+ log('┌ %smetapost instance {%s} (%d)', why or '', i.jobname, i.nr)
for _,line in ipairs(report) do
- log('│ %s', line)
+ if line ~= '' and line ~= "(Please type a command or say `end')" then
+ log('│ %s', line)
+ end
end
log('└ %s', print_status(res.status))
-- generate error or warning if needed
if res.status > i.status then
+ local ecl = tex.errorcontextlines -- TODO: why does TeX fill the error context
+ tex.errorcontextlines = 0 -- with repeated <inserted text> BAD ???
if res.status == 3 then
alloc.err('Metapost instance now defunct')
elseif res.status == 2 then
@@ -1068,6 +1083,7 @@ local function print_log (nr, res, why)
elseif res.status == 1 then
alloc.msg('Metapost code caused warning')
end
+ tex.errorcontextlines = ecl
end
-- save the exit status for later comparison
i.status = res.status
@@ -1107,6 +1123,9 @@ local function process_results(nr, res)
local fig = res.fig[i]
local name = fig:filename()
local append = init_append()
+ if debugging then
+ append:literal('%% START OF MP FIGURE %s (instance %d)', name, nr)
+ end
-- parse and append all objects
append:save()
local objects = fig:objects()
@@ -1114,6 +1133,9 @@ local function process_results(nr, res)
parse_object (append, objects[j])
end
append:restore()
+ if debugging then
+ append:literal('%% END OF MP FIGURE %s (instance %d)', name, nr)
+ end
-- bounding box and baseline information
local bb = fig:boundingbox()
local llx, lly, urx, ury = table.unpack(bb)
@@ -1174,12 +1196,19 @@ end
-- change in the future.)
local function mkluastring(s)
- return "'"..(s:gsub('\\', '\\\\'):gsub("'", "\\'"):gsub('\n', '\\n')).."'"
+ return "'"..(s
+ :gsub('\\', '\\\\')
+ :gsub("'", "\\'")
+ :gsub('\n', '\\n')
+ :gsub('\013', '\\r')
+ :gsub('\000', '\\000')
+ ).."'"
end
local function runscript(code)
+ debug('┌ runscript: %s', code)
-- (possibly) pass directly to function
- local fn, arg = code:match('^%[%[(.+)%]%](.*)')
+ local fn, arg = code:match('^%[%[(.-)%]%](.*)')
if fn then code = 'return '..fn .. mkluastring(arg) end
-- execute the script
local f, msg = load(code, current_instance.jobname, 't', current_instance.env)
@@ -1187,32 +1216,39 @@ local function runscript(code)
if f then
local result = f()
if result == nil then
+ debug('└ (no return value)')
return
else
local t = type(result)
if t == 'number' then
- return string.format('%.16f', result)
+ result = string.format('%.16f', result)
elseif t == 'string' then
- return result
+ result = result
elseif t == 'table' and result[1] == 'box_size' then
- return make_transform(result[2], result[3], result[4])
+ result = make_transform(result[2], result[3], result[4])
elseif t == 'table' and #result < 5 then
local fmt = #result == 1 and '%.16f'
or #result == 2 and '(%.16f, %.16f)'
or #result == 3 and '(%.16f, %.16f, %.16f)'
or #result == 4 and '(%.16f, %.16f, %.16f, %.16f)'
- return fmt:format(table.unpack(result))
+ result = fmt:format(table.unpack(result))
elseif t == 'table' and #result == 6 then
- return table.concat({
- 'begingroup save t; transform t;',
+ result = table.concat({
+ 'begingroup save t; transform t',
'xxpart t = %.16f', 'xypart t = %.16f',
'yxpart t = %.16f', 'yypart t = %.16f',
'xpart t = %.16f', 'ypart t = %.16f',
't endgroup' },
';'):format(table.unpack(result))
else
- return tostring(result)
+ result = tostring(result)
end
+ if #result > 120 then
+ debug('└ %s etc. etc.', result:sub(1,110))
+ else
+ debug('└ %s', result)
+ end
+ return result
end
else
local mp_msg = string.gsub(msg, '"', '"&ditto&"')
@@ -1257,7 +1293,8 @@ E.catcodes = { numbers =
, vrbcatcodes = cct_maketext , prtcatcodes = cct_maketext
, ctxcatcodes = cct_maketext , txtcatcodes = cct_maketext
} }
-E.mp = mp or { } -- all seem nonessential
+E.mp = mp or { } --luacheck: ignore 113
+-- all functions below seem nonessential
E.mp.mf_path_reset = E.mp.mf_path_reset or function() end
E.mp.mf_finish_saving_data = E.mp.mf_finish_saving_data or function() end
E.mp.report = E.mp.report or function() end
@@ -1283,19 +1320,51 @@ E.mp.report = E.mp.report or function() end
local function maketext(text, mode)
if mode == 0 then -- btex or maketext
local nr = alloc.new_box()
+ debug('┌ btex: %s', text)
table.insert(current_instance.boxes, nr)
local assignment = string.format('\\global\\setbox%s=\\hbox{\\the\\everymaketext %s}', nr, text)
tex.runtoks(function() tex.print(current_instance.catcodes, assignment:explode('\n')) end)
local box = tex.box[nr]
+ debug('└ etex: box %d', nr)
return string.format('_set_maketext_result_(%d, %s)', nr,
make_transform(box.width, box.height, box.depth))
elseif mode == 1 then -- verbatimtex
+ debug('┌ verbatimtex: %s', text)
tex.runtoks(function() tex.print(current_instance.catcodes, text:explode('\n')) end)
+ debug('└ etex')
+ end
+end
+
+-- a font cache for infont and glyph of
+local infont_fonts = { }
+local function get_infont_font(fnt)
+ local csname = 'minim-mp infont '..fnt
+ local res = infont_fonts[csname]
+ if res then
+ debug('├ resolved font "%s" (%d)', fnt, res)
+ else
+ tex.runtoks(function()
+ tex.print(current_instance.catcodes, string.format(
+ '\\expandafter\\font\\csname %s\\endcsname={%s}\\relax', csname, fnt))
+ end)
+ res = font.id(csname)
+ infont_fonts[csname] = res
+ debug('├ loaded font "%s" (%d)', fnt, res)
end
+ return res
+end
+
+local function fontid_from_csname(fnt)
+ local id = font.id(fnt)
+ if id < 0 then return end
+ debug('├ resolved font \\%s (%d)', fnt, id)
+ return id
end
local function getfontid(fnt)
- return tonumber(fnt) or font.id(fnt)
+ return tonumber(fnt)
+ or fontid_from_csname(fnt)
+ or get_infont_font(fnt)
end
local typeset_box = alloc.new_box('infont box')
@@ -1377,17 +1446,23 @@ function M.make_glyph(glyphname, fnt)
end
local function get_glyphname(c_id)
- return luaotfload.aux.name_of_slot(c_id)
+ if type(c_id) == 'string' then return c_id end
+ local res = luaotfload.aux.name_of_slot(c_id)
+ debug('├ name of glyph %d is %s', c_id, res)
+ return res
end
function E.get_glyph(c_id, fnt)
- local name = (type(c_id) == 'string') and c_id or get_glyphname(c_id)
+ debug('┌ glyph %s of %s', c_id, fnt)
+ local name = get_glyphname(c_id)
local contours, size = M.make_glyph(name, fnt)
local res = { }
for _, c in ipairs(contours) do
- table.insert(res, string.format(
- '%s scaled %f', c, size/65536/1000))
+ local scaled = string.format('%s scaled %f', c, size/65536/1000)
+ debug('│ %s', scaled)
+ table.insert(res, scaled)
end
+ debug('└ %d contours returned', #res)
return table.concat(res, ', ')
end
@@ -1419,7 +1494,7 @@ local function apply_default_instance_opts(t)
--, script_error = ...
, job_name = t.jobname
, math_mode = t.mathmode or t.math or M.default_mathmode
- , random_seed = t.seed or nil
+ , random_seed = t.randomseed or t.seed or nil
-- , file_line_error_style
, make_text = maketext
, run_script = runscript
@@ -1451,7 +1526,17 @@ function M.run (nr, code)
return
end
current_instance = self
+ if debugging then
+ alloc.log('┌ metapost chunk for {%s} (%d)', self.jobname, nr)
+ for _, line in ipairs(code:explode('\013')) do
+ alloc.log('│ %s', line)
+ end
+ alloc.log('└')
+ end
+ local cct = tex.catcodetable
+ tex.catcodetable = self.catcodes
local res = self.instance:execute(code)
+ tex.catcodetable = cct
print_log(nr, res)
local picts = process_results(nr, res)
save_image_list(self, picts)
@@ -1460,17 +1545,19 @@ end
M.init_code = { 'let dump=endinput;'
, 'boolean mplib; mplib:=true;'
, 'input INIT;'
- , 'input minim-mp.mp;'
- , 'input minim.mp;' }
+ , 'input minim.mp;'
+ , 'input minim-mp.mp;' }
local maketext_catcodes = alloc.registernumber('minim:mp:catcodes:maketext')
function M.open (t)
local nr = #instances + 1
- t.jobname = t.jobname or ':metapost:'
+ tex.count['mp:cur:inst'] = nr
-- creating instance options
+ t.jobname = t.jobname or ':metapost:'
local init = string.gsub(table.concat(M.init_code, ''), 'INIT', t.format or M.default_format)
local opts = apply_default_instance_opts(t)
local instance = mplib.new(opts)
+ tex.runtoks 'mp:init:env'
-- adding the instance
instances[nr] =
{ nr = nr
@@ -1484,11 +1571,13 @@ function M.open (t)
}
current_instance = instances[nr]
print_log(nr, instance:execute(init), 'opening ')
+ tex.count['mp:cur:inst'] = -1
return nr
end
function M.close (nr)
local i = instances[nr]
+ tex.count['mp:cur:inst'] = nr
if i.instance then
local res = i.instance:finish()
print_log(nr, res, 'closing ')
@@ -1498,6 +1587,7 @@ function M.close (nr)
tex.box[b] = nil
end
instances[nr] = false
+ tex.count['mp:cur:inst'] = -1
end
-- 2 retrieving and using results
@@ -1569,25 +1659,30 @@ end
local scan_int = token.scan_int
local scan_string = token.scan_string
+alloc.luadef('closemetapostinstance', function() M.close(scan_int()) end)
+
local code_catcodes = alloc.registernumber('minim:mp:catcodes:mpcode')
-local function scan_codestring()
+
+alloc.luadef('runmetapost', function()
+ local id = scan_int()
+ tex.count['mp:cur:inst'] = id
+ -- run tex code before
+ tex.runtoks 'mp:inst:pre:tex'
+ -- scan the argument with inert catcodes
local cct = tex.catcodetable
tex.catcodetable = code_catcodes
- local res = token.scan_string()
+ token.scan_keyword '\013' -- ^^M has catcode 12 now
+ local code = token.scan_string()
tex.catcodetable = cct
- return res
-end
-
-alloc.luadef('closemetapostinstance', function() M.close(scan_int()) end)
-
-alloc.luadef('runmetapost', function()
- M.run(scan_int(), scan_codestring())
-end, 'protected')
-alloc.luadef('runmetapostimage', function()
- local i = scan_int()
- local code = 'beginfig(0)'..scan_codestring()..';endfig;'
- M.run(i, code)
- node.write(M.get_image(i))
+ -- prepare the argument further
+ tex.toks['mp:mpcode'] = code
+ tex.runtoks 'mp:makempcode'
+ code = tex.toks['mp:mpcode']
+ -- run the code
+ M.run(id, code)
+ -- run tech code after
+ tex.runtoks 'mp:inst:post:tex'
+ tex.count['mp:cur:inst'] = -1
end, 'protected')
alloc.luadef('getnextmpimage', function()