1if not modules then modules = { } end modules ['mlib-ctx'] = {
2 version = 1.001,
3 comment = "companion to mlib-ctx.mkiv",
4 author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5 copyright = "PRAGMA ADE / ConTeXt Development Team",
6 license = "see context related readme files",
7}
8
9local type, tostring = type, tostring
10local format, concat = string.format, table.concat
11local settings_to_hash = utilities.parsers.settings_to_hash
12local formatters = string.formatters
13
14local report_metapost = logs.reporter ("metapost")
15local status_metapost = logs.messenger("metapost")
16
17local starttiming = statistics.starttiming
18local stoptiming = statistics.stoptiming
19
20local trace_graphic = false
21
22trackers.register("metapost.graphics",
23 function(v) trace_graphic = v end
24);
25
26local mplib = mplib
27
28metapost = metapost or { }
29local metapost = metapost
30local context = context
31
32local setters = tokens.setters
33local setmacro = setters.macro
34local implement = interfaces.implement
35
36local v_no <const> = interfaces.variables.no
37
38local extensiondata = metapost.extensiondata or storage.allocate { }
39metapost.extensiondata = extensiondata
40
41storage.register("metapost/extensiondata",extensiondata,"metapost.extensiondata")
42
43function metapost.setextensions(instances,data)
44 if data and data ~= "" then
45 extensiondata[#extensiondata+1] = {
46 usedinall = not instances or instances == "",
47 instances = settings_to_hash(instances or ""),
48 extensions = data,
49 }
50 end
51end
52
53function metapost.getextensions(instance,state)
54 if state and state == v_no then
55 return ""
56 else
57 local t = { }
58 for i=1,#extensiondata do
59 local e = extensiondata[i]
60 local status = e.instances[instance]
61 if (status ~= true) and (e.usedinall or status) then
62 t[#t+1] = e.extensions
63 e.instances[instance] = true
64 end
65 end
66 return concat(t," ")
67 end
68end
69
70implement {
71 name = "setmpextensions",
72 actions = metapost.setextensions,
73 arguments = "2 strings",
74}
75
76implement {
77 name = "getmpextensions",
78 actions = { metapost.getextensions, context } ,
79 arguments = "string"
80}
81
82local patterns = {
83 "meta-imp-%s.mkxl",
84 "meta-imp-%s.mkiv",
85 "meta-imp-%s.tex",
86
87 "meta-%s.mkiv",
88 "meta-%s.tex"
89}
90
91local function action(name,foundname)
92 commands.loadlibrary(name,foundname,false)
93 status_metapost("library %a is loaded",name)
94end
95
96local function failure(name)
97 report_metapost("library %a is unknown or invalid",name)
98end
99
100implement {
101 name = "useMPlibrary",
102
103 arguments = "optional",
104 public = true,
105 protected = true,
106 actions = function(name)
107 resolvers.uselibrary {
108 name = name,
109 patterns = patterns,
110 action = action,
111 failure = failure,
112 onlyonce = true,
113 }
114 end
115}
116
117
118
119implement {
120 name = "mprunvar",
121 arguments = "string",
122 actions = function(name)
123 local value = metapost.variables[name]
124 local tvalue = type(value)
125 if tvalue == "nil" then
126 context("0")
127 elseif tvalue == "table" then
128 context(concat(value," "))
129 elseif tvalue == "number" or tvalue == "boolean" then
130 context(tostring(value))
131 elseif tvalue == "string" then
132 context(value)
133 end
134 end
135}
136
137implement {
138 name = "mpruntab",
139 arguments = { "string", "integer" },
140 actions = function(name,n)
141 local value = metapost.variables[name]
142 if value ~= nil then
143 local tvalue = type(value)
144 if tvalue == "table" then
145 context(value[n])
146 elseif tvalue == "number" or tvalue == "boolean" then
147 context(tostring(value))
148 elseif tvalue == "string" then
149 context(value)
150 end
151 end
152 end
153}
154
155implement {
156 name = "mprunset",
157 arguments = "2 strings",
158 actions = function(name,connector)
159 local value = metapost.variables[name]
160 if value ~= nil then
161 local tvalue = type(value)
162 if tvalue == "table" then
163 context(concat(value,connector))
164 elseif tvalue == "number" or tvalue == "boolean" then
165 context(tostring(value))
166 elseif tvalue == "string" then
167 context(value)
168 end
169 end
170 end
171}
172
173
174
175
176function metapost.graphic(specification)
177 metapost.pushformat(specification)
178 metapost.graphic_base_pass(specification)
179 metapost.popformat()
180end
181
182function metapost.startgraphic(t)
183 if not t then
184 t = { }
185 end
186 if not t.instance then
187 t.instance = metapost.defaultinstance
188 end
189 if not t.format then
190 t.format = metapost.defaultformat
191 end
192 if not t.method then
193 t.method = metapost.defaultmethod
194 end
195 t.data = { }
196 return t
197end
198
199function metapost.stopgraphic(t)
200 if t then
201 t.data = concat(t.data or { },"\n")
202 if trace_graphic then
203 report_metapost("\n"..t.data.."\n")
204 end
205 metapost.graphic(t)
206 end
207end
208
209function metapost.tographic(t,f,s,...)
210 local d = t.data
211 d[#d+1] = s and formatters[f](s,...) or f
212end
213
214implement {
215 name = "mpgraphic",
216 actions = metapost.graphic,
217 arguments = {
218 {
219 { "instance" },
220 { "format" },
221 { "data" },
222 { "initializations" },
223 { "extensions" },
224 { "inclusions" },
225 { "definitions" },
226 { "figure" },
227 { "method" },
228 { "namespace" },
229 { "filtering" },
230 }
231 }
232}
233
234implement {
235 name = "mpsetoutercolor",
236 actions = function(...) metapost.setoutercolor(...) end,
237 arguments = "4 integers",
238}
239
240
241
242function metapost.getclippath(specification)
243 local mpx = metapost.pushformat(specification)
244 local data = specification.data or ""
245 if mpx and data ~= "" then
246 starttiming(metapost)
247 starttiming(metapost.exectime)
248 local result = mpx:execute ( format ( "%s;%s;beginfig(1);%s;%s;endfig;",
249 specification.extensions or "",
250 specification.inclusions or "",
251 specification.initializations or "",
252 data
253 ) )
254 stoptiming(metapost.exectime)
255 if result.status > 0 then
256 report_metapost("%s: %s", result.status, result.error or result.term or result.log)
257 result = nil
258 else
259 result = metapost.filterclippath(result)
260 end
261 stoptiming(metapost)
262 metapost.popformat()
263 return result
264 else
265 metapost.popformat()
266 end
267end
268
269function metapost.filterclippath(result)
270 if result then
271 local figures = result.fig
272 if figures and #figures > 0 then
273 local figure = figures[1]
274 local objects = figure:objects()
275 if objects then
276 local lastclippath
277 for o=1,#objects do
278 local object = objects[o]
279 if object.type == "start_clip" then
280 lastclippath = object.path
281 end
282 end
283 return lastclippath
284 end
285 end
286 end
287end
288
289function metapost.theclippath(...)
290 local result = metapost.getclippath(...)
291 if result then
292 return concat(metapost.flushnormalpath(result)," ")
293 else
294 return ""
295 end
296end
297
298implement {
299 name = "mpsetclippath",
300 actions = function(specification)
301 local p = specification.data and metapost.theclippath(specification)
302 if not p or p == "" then
303 local b = number.dimenfactors.bp
304 local w = b * (specification.width or 0)
305 local h = b * (specification.height or 0)
306 p = formatters["0 0 m %.6N 0 l %.6N %.6N l 0 %.6N l"](w,w,h,h)
307 end
308 setmacro("MPclippath",p,"global")
309 end,
310 arguments = {
311 {
312 { "instance" },
313 { "format" },
314 { "data" },
315 { "initializations" },
316 { "useextensions" },
317 { "inclusions" },
318 { "method" },
319 { "namespace" },
320 { "filtering" },
321 { "width", "dimension" },
322 { "height", "dimension" },
323 },
324 }
325}
326
327statistics.register("metapost", function()
328 local n = metapost.nofruns
329 if n and n > 0 then
330 local elapsedtime = statistics.elapsedtime
331 local elapsed = statistics.elapsed
332 local runs, stats = metapost.nofscriptruns()
333 local instances,
334 memory = metapost.getstatistics(true)
335 return format("%s seconds, loading: %s, execution: %s, n: %s, average: %s, instances: %i, luacalls: %s, memory: %0.3f M",
336 elapsedtime(metapost), elapsedtime(mplib), elapsedtime(metapost.exectime), n,
337 elapsedtime((elapsed(metapost) + elapsed(mplib) + elapsed(metapost.exectime)) / n),
338 instances, stats and stats or runs, memory/(1024*1024))
339 else
340 return nil
341 end
342end)
343
344
345
346metapost.tex = metapost.tex or { }
347local mptex = metapost.tex
348
349local environments = { }
350
351function mptex.set(str)
352 environments[#environments+1] = str
353end
354
355function mptex.setfrombuffer(name)
356 environments[#environments+1] = buffers.getcontent(name)
357end
358
359function mptex.get()
360 return concat(environments,"\n")
361end
362
363function mptex.reset()
364 environments = { }
365end
366
367implement {
368 name = "mptexset",
369 arguments = "string",
370 actions = mptex.set
371}
372
373implement {
374 name = "mptexsetfrombuffer",
375 arguments = "string",
376 actions = mptex.setfrombuffer
377}
378
379implement {
380 name = "mptexget",
381 actions = { mptex.get, context }
382}
383
384implement {
385 name = "mptexreset",
386 actions = mptex.reset
387}
388
389
390
391mp = mp or {
392 set = { },
393 get = { },
394 aux = { },
395 scan = { },
396 skip = { },
397 inject = { },
398}
399
400MP = MP or { }
401
402
403
404
405
406
407
408
409
410
411
412
413
414table.setmetatablecall(mp,function(t,k,...) return t[k](...) end)
415table.setmetatablecall(MP,function(t,k,...) return t[k](...) end)
416
417
418
419implement {
420 name = "resetMPinstance",
421 protected = true,
422 public = true,
423 arguments = "optional",
424 actions = function(s)
425 if s and s ~= "" then
426 report_metapost("resetting instance %a",s)
427 metapost.reset(s)
428 end
429 end,
430}
431 |