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 = 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 arguments = "string",
103 actions = function(name)
104 resolvers.uselibrary {
105 name = name,
106 patterns = patterns,
107 action = action,
108 failure = failure,
109 onlyonce = true,
110 }
111 end
112}
113
114
115
116implement {
117 name = "mprunvar",
118 arguments = "string",
119 actions = function(name)
120 local value = metapost.variables[name]
121 local tvalue = type(value)
122 if tvalue == "nil" then
123 context("0")
124 elseif tvalue == "table" then
125 context(concat(value," "))
126 elseif tvalue == "number" or tvalue == "boolean" then
127 context(tostring(value))
128 elseif tvalue == "string" then
129 context(value)
130 end
131 end
132}
133
134implement {
135 name = "mpruntab",
136 arguments = { "string", "integer" },
137 actions = function(name,n)
138 local value = metapost.variables[name]
139 if value ~= nil then
140 local tvalue = type(value)
141 if tvalue == "table" then
142 context(value[n])
143 elseif tvalue == "number" or tvalue == "boolean" then
144 context(tostring(value))
145 elseif tvalue == "string" then
146 context(value)
147 end
148 end
149 end
150}
151
152implement {
153 name = "mprunset",
154 arguments = "2 strings",
155 actions = function(name,connector)
156 local value = metapost.variables[name]
157 if value ~= nil then
158 local tvalue = type(value)
159 if tvalue == "table" then
160 context(concat(value,connector))
161 elseif tvalue == "number" or tvalue == "boolean" then
162 context(tostring(value))
163 elseif tvalue == "string" then
164 context(value)
165 end
166 end
167 end
168}
169
170
171
172
173function metapost.graphic(specification)
174 metapost.pushformat(specification)
175 metapost.graphic_base_pass(specification)
176 metapost.popformat()
177end
178
179function metapost.startgraphic(t)
180 if not t then
181 t = { }
182 end
183 if not t.instance then
184 t.instance = metapost.defaultinstance
185 end
186 if not t.format then
187 t.format = metapost.defaultformat
188 end
189 if not t.method then
190 t.method = metapost.defaultmethod
191 end
192 t.data = { }
193 return t
194end
195
196function metapost.stopgraphic(t)
197 if t then
198 t.data = concat(t.data or { },"\n")
199 if trace_graphic then
200 report_metapost("\n"..t.data.."\n")
201 end
202 metapost.graphic(t)
203 end
204end
205
206function metapost.tographic(t,f,s,...)
207 local d = t.data
208 d[#d+1] = s and formatters[f](s,...) or f
209end
210
211implement {
212 name = "mpgraphic",
213 actions = metapost.graphic,
214 arguments = {
215 {
216 { "instance" },
217 { "format" },
218 { "data" },
219 { "initializations" },
220 { "extensions" },
221 { "inclusions" },
222 { "definitions" },
223 { "figure" },
224 { "method" },
225 { "namespace" },
226 { "filtering" },
227 }
228 }
229}
230
231implement {
232 name = "mpsetoutercolor",
233 actions = function(...) metapost.setoutercolor(...) end,
234 arguments = "4 integers",
235}
236
237
238
239function metapost.getclippath(specification)
240 local mpx = metapost.pushformat(specification)
241 local data = specification.data or ""
242 if mpx and data ~= "" then
243 starttiming(metapost)
244 starttiming(metapost.exectime)
245 local result = mpx:execute ( format ( "%s;%s;beginfig(1);%s;%s;endfig;",
246 specification.extensions or "",
247 specification.inclusions or "",
248 specification.initializations or "",
249 data
250 ) )
251 stoptiming(metapost.exectime)
252 if result.status > 0 then
253 report_metapost("%s: %s", result.status, result.error or result.term or result.log)
254 result = nil
255 else
256 result = metapost.filterclippath(result)
257 end
258 stoptiming(metapost)
259 metapost.popformat()
260 return result
261 else
262 metapost.popformat()
263 end
264end
265
266function metapost.filterclippath(result)
267 if result then
268 local figures = result.fig
269 if figures and #figures > 0 then
270 local figure = figures[1]
271 local objects = figure:objects()
272 if objects then
273 local lastclippath
274 for o=1,#objects do
275 local object = objects[o]
276 if object.type == "start_clip" then
277 lastclippath = object.path
278 end
279 end
280 return lastclippath
281 end
282 end
283 end
284end
285
286function metapost.theclippath(...)
287 local result = metapost.getclippath(...)
288 if result then
289 return concat(metapost.flushnormalpath(result)," ")
290 else
291 return ""
292 end
293end
294
295implement {
296 name = "mpsetclippath",
297 actions = function(specification)
298 local p = specification.data and metapost.theclippath(specification)
299 if not p or p == "" then
300 local b = number.dimenfactors.bp
301 local w = b * (specification.width or 0)
302 local h = b * (specification.height or 0)
303 p = formatters["0 0 m %.6N 0 l %.6N %.6N l 0 %.6N l"](w,w,h,h)
304 end
305 setmacro("MPclippath",p,"global")
306 end,
307 arguments = {
308 {
309 { "instance" },
310 { "format" },
311 { "data" },
312 { "initializations" },
313 { "useextensions" },
314 { "inclusions" },
315 { "method" },
316 { "namespace" },
317 { "filtering" },
318 { "width", "dimension" },
319 { "height", "dimension" },
320 },
321 }
322}
323
324statistics.register("metapost", function()
325 local n = metapost.nofruns
326 if n and n > 0 then
327 local elapsedtime = statistics.elapsedtime
328 local elapsed = statistics.elapsed
329 local runs, stats = metapost.nofscriptruns()
330 local instances,
331 memory = metapost.getstatistics(true)
332 return format("%s seconds, loading: %s, execution: %s, n: %s, average: %s, instances: %i, luacalls: %s, memory: %0.3f M",
333 elapsedtime(metapost), elapsedtime(mplib), elapsedtime(metapost.exectime), n,
334 elapsedtime((elapsed(metapost) + elapsed(mplib) + elapsed(metapost.exectime)) / n),
335 instances, stats and stats or runs, memory/(1024*1024))
336 else
337 return nil
338 end
339end)
340
341
342
343metapost.tex = metapost.tex or { }
344local mptex = metapost.tex
345
346local environments = { }
347
348function mptex.set(str)
349 environments[#environments+1] = str
350end
351
352function mptex.setfrombuffer(name)
353 environments[#environments+1] = buffers.getcontent(name)
354end
355
356function mptex.get()
357 return concat(environments,"\n")
358end
359
360function mptex.reset()
361 environments = { }
362end
363
364implement {
365 name = "mptexset",
366 arguments = "string",
367 actions = mptex.set
368}
369
370implement {
371 name = "mptexsetfrombuffer",
372 arguments = "string",
373 actions = mptex.setfrombuffer
374}
375
376implement {
377 name = "mptexget",
378 actions = { mptex.get, context }
379}
380
381implement {
382 name = "mptexreset",
383 actions = mptex.reset
384}
385
386
387
388mp = mp or {
389 set = { },
390 get = { },
391 aux = { },
392 scan = { },
393 skip = { },
394 inject = { },
395}
396
397MP = MP or { }
398
399
400
401
402
403
404
405
406
407
408
409
410
411table.setmetatablecall(mp,function(t,k,...) return t[k](...) end)
412table.setmetatablecall(MP,function(t,k,...) return t[k](...) end)
413
414
415
416implement {
417 name = "resetMPinstance",
418 protected = true,
419 public = true,
420 arguments = "optional",
421 actions = function(s)
422 if s and s ~= "" then
423 report_metapost("resetting instance %a",s)
424 metapost.reset(s)
425 end
426 end,
427}
428 |