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 CONTEXTLMTXMODE > 0 and "meta-imp-%s.mkxl" or "",
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 if value ~= nil then
122 local tvalue = type(value)
123 if tvalue == "table" then
124 context(concat(value," "))
125 elseif tvalue == "number" or tvalue == "boolean" then
126 context(tostring(value))
127 elseif tvalue == "string" then
128 context(value)
129 end
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 }
227 }
228}
229
230implement {
231 name = "mpsetoutercolor",
232 actions = function(...) metapost.setoutercolor(...) end,
233 arguments = { "integer", "integer", "integer", "integer" }
234}
235
236implement {
237 name = "mpflushreset",
238 actions = function() metapost.flushreset() end
239}
240
241implement {
242 name = "mpflushliteral",
243 actions = function(str) metapost.flushliteral(str) end,
244 arguments = "string",
245}
246
247
248
249function metapost.getclippath(specification)
250 local mpx = metapost.pushformat(specification)
251 local data = specification.data or ""
252 if mpx and data ~= "" then
253 starttiming(metapost)
254 starttiming(metapost.exectime)
255 local result = mpx:execute ( format ( "%s;%s;beginfig(1);%s;%s;endfig;",
256 specification.extensions or "",
257 specification.inclusions or "",
258 specification.initializations or "",
259 data
260 ) )
261 stoptiming(metapost.exectime)
262 if result.status > 0 then
263 report_metapost("%s: %s", result.status, result.error or result.term or result.log)
264 result = nil
265 else
266 result = metapost.filterclippath(result)
267 end
268 stoptiming(metapost)
269 metapost.popformat()
270 return result
271 else
272 metapost.popformat()
273 end
274end
275
276function metapost.filterclippath(result)
277 if result then
278 local figures = result.fig
279 if figures and #figures > 0 then
280 local figure = figures[1]
281 local objects = figure:objects()
282 if objects then
283 local lastclippath
284 for o=1,#objects do
285 local object = objects[o]
286 if object.type == "start_clip" then
287 lastclippath = object.path
288 end
289 end
290 return lastclippath
291 end
292 end
293 end
294end
295
296function metapost.theclippath(...)
297 local result = metapost.getclippath(...)
298 if result then
299 return concat(metapost.flushnormalpath(result)," ")
300 else
301 return ""
302 end
303end
304
305implement {
306 name = "mpsetclippath",
307 actions = function(specification)
308 local p = specification.data and metapost.theclippath(specification)
309 if not p or p == "" then
310 local b = number.dimenfactors.bp
311 local w = b * (specification.width or 0)
312 local h = b * (specification.height or 0)
313 p = formatters["0 0 m %.6N 0 l %.6N %.6N l 0 %.6N l"](w,w,h,h)
314 end
315 setmacro("MPclippath",p,"global")
316 end,
317 arguments = {
318 {
319 { "instance" },
320 { "format" },
321 { "data" },
322 { "initializations" },
323 { "useextensions" },
324 { "inclusions" },
325 { "method" },
326 { "namespace" },
327 { "width", "dimension" },
328 { "height", "dimension" },
329 },
330 }
331}
332
333statistics.register("metapost", function()
334 local n = metapost.nofruns
335 if n and n > 0 then
336 local elapsedtime = statistics.elapsedtime
337 local elapsed = statistics.elapsed
338 local runs, stats = metapost.nofscriptruns()
339 local instances,
340 memory = metapost.getstatistics(true)
341 return format("%s seconds, loading: %s, execution: %s, n: %s, average: %s, instances: %i, luacalls: %s, memory: %0.3f M",
342 elapsedtime(metapost), elapsedtime(mplib), elapsedtime(metapost.exectime), n,
343 elapsedtime((elapsed(metapost) + elapsed(mplib) + elapsed(metapost.exectime)) / n),
344 instances, stats and stats or runs, memory/(1024*1024))
345 else
346 return nil
347 end
348end)
349
350
351
352metapost.tex = metapost.tex or { }
353local mptex = metapost.tex
354
355local environments = { }
356
357function mptex.set(str)
358 environments[#environments+1] = str
359end
360
361function mptex.setfrombuffer(name)
362 environments[#environments+1] = buffers.getcontent(name)
363end
364
365function mptex.get()
366 return concat(environments,"\n")
367end
368
369function mptex.reset()
370 environments = { }
371end
372
373implement {
374 name = "mppushvariables",
375 actions = metapost.pushvariables,
376}
377
378implement {
379 name = "mppopvariables",
380 actions = metapost.popvariables,
381}
382
383implement {
384 name = "mptexset",
385 arguments = "string",
386 actions = mptex.set
387}
388
389implement {
390 name = "mptexsetfrombuffer",
391 arguments = "string",
392 actions = mptex.setfrombuffer
393}
394
395implement {
396 name = "mptexget",
397 actions = { mptex.get, context }
398}
399
400implement {
401 name = "mptexreset",
402 actions = mptex.reset
403}
404
405
406
407mp = mp or {
408 set = { },
409 get = { },
410 aux = { },
411 scan = { },
412 skip = { },
413 inject = { },
414}
415
416MP = MP or { }
417
418
419
420
421
422
423
424
425
426
427
428
429
430table.setmetatablecall(mp,function(t,k,...) return t[k](...) end)
431table.setmetatablecall(MP,function(t,k,...) return t[k](...) end)
432 |