1if not modules then modules = { } end modules ['mlib-lmp'] = {
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
9
10
11local type, tonumber, tostring = type, tonumber, tostring
12local setmetatable, setmetatableindex = setmetatable, table.setmetatableindex
13local find, match = string.find, string.match
14local insert, remove, sort = table.insert, table.remove, table.sort
15
16local aux = mp.aux
17local mpnumeric = aux.numeric
18local mppair = aux.pair
19
20local registerdirect = metapost.registerdirect
21local registerscript = metapost.registerscript
22
23local scan = mp.scan
24local skip = mp.skip
25local get = mp.get
26local inject = mp.inject
27
28local scannumber = scan.number
29local scanstring = scan.string
30local scaninteger = scan.integer
31local scannumeric = scan.numeric
32local scanwhatever = scan.whatever
33local scanpath = scan.path
34local scanproperty = scan.property
35
36local gethashentry = get.hashentry
37
38local bpfactor <const> = number.dimenfactors.bp
39
40local injectwhatever = inject.whatever
41local injectboolean = inject.boolean
42local injectnumeric = inject.numeric
43local injectstring = inject.string
44local injectpair = inject.pair
45local injectpath = inject.path
46
47local injectwhd = inject.whd
48local injectxy = inject.xy
49local injectpt = inject.pt
50
51local report = logs.reporter("metapost", "log")
52local report_message = logs.reporter("metapost")
53
54local codes = metapost.codes
55local types = metapost.types
56local procodes = mplib.propertycodes
57
58local implement = interfaces.implement
59
60do
61
62 local function s(a,b)
63 local aa = a[1]
64 local bb = b[1]
65 if aa == bb then
66 aa = a[2]
67 bb = b[2]
68 end
69 return aa < bb
70 end
71
72 registerscript("sortedpath", function()
73 local p = scanpath()
74 for i=1,#p do
75 local pi = p[i]
76 p[i] = { pi[1], pi[2] }
77 end
78 sort(p,s)
79 injectpath(p)
80 end)
81
82 registerscript("uniquepath", function()
83 local p = scanpath()
84 local u = { }
85 local n = 0
86 local xx = nil
87 local yy = nil
88 sort(p,s)
89 for i=1,#p do
90 local pi = p[i]
91 local x = pi[1]
92 local y = pi[2]
93 if x ~= xx or y ~= yy then
94 n = n + 1
95 u[n] = { x, y }
96 xx = x
97 yy = y
98 end
99 end
100 injectpath(u)
101 end)
102
103end
104
105do
106
107 local p = nil
108 local n = 0
109
110 registerscript("pathreset", function()
111 p = nil
112 n = 0
113 end)
114
115 registerdirect("pathlengthof", function()
116 p = scanpath()
117 n = p and #p or 1
118 return n
119 end)
120
121 registerdirect("pathpointof", function()
122 local i = scaninteger()
123 if i > 0 and i <= n then
124 local pi = p[i]
125 injectpair(pi[1],pi[2])
126 end
127 end)
128
129 registerdirect("pathleftof", function()
130 local i = scaninteger()
131 if i > 0 and i <= n then
132 local pi = p[i]
133 injectpair(pi[5],pi[6])
134 end
135 end)
136
137 registerdirect("pathrightof", function()
138 local i = scaninteger()
139 if i > 0 and i <= n then
140 local pn
141 if i == 1 then
142 pn = p[2] or p[1]
143 else
144 pn = p[i+1] or p[1]
145 end
146 injectpair(pn[3],pn[4])
147 end
148 end)
149
150end
151
152registerscript("showproperty", function()
153 local k, s, p, d = scanproperty()
154 if k then
155 report("name %a, property %a, command %a, detail %a",s,procodes[p] or "-",codes[k] or "-",types[d] or "-")
156 end
157end)
158
159registerscript("showhashentry", function()
160 local s = scanstring()
161 if s then
162 local k, p, d = gethashentry(s)
163 if k then
164 report("name %a, property %a, command %a, detail %a",s,procodes[p] or "-",codes[k] or "-",types[d] or "-")
165 end
166 end
167end)
168
169
170
171
172
173
174
175
176
177
178
179do
180
181 local expandtex = mp.expandtex
182
183 local tokenvalues = tokens.values
184 local dimension_value <const> = tokenvalues.dimension
185 local integer_value <const> = tokenvalues.integer
186 local boolean_value <const> = tokenvalues.boolean
187 local string_value <const> = tokenvalues.string
188 local unknown_value <const> = tokenvalues.none
189
190 registerdirect("mpvard", function()
191 if not expandtex(dimension_value,"mpcategoryparameter",true,scanstring()) then
192 injectnumeric(0)
193 end
194 end)
195
196 registerdirect("mpvarn", function()
197 if not expandtex(integer_value,"mpcategoryparameter",true,scanstring()) then
198 injectnumeric(0)
199 end
200 end)
201
202 registerdirect("mpvars", function()
203 if not expandtex(string_value,"mpcategoryparameter",true,scanstring()) then
204 injectstring("")
205 end
206 end)
207
208 registerdirect("mpvarb", function()
209 if not expandtex(boolean_value,"mpcategoryparameter",true,scanstring()) then
210 injectboolean(false)
211 end
212 end)
213
214 registerdirect("mpvar", function()
215 if not expandtex(unknown_value,"mpcategoryparameter",true,scanstring()) then
216 injectnumeric(0)
217 end
218 end)
219
220
221
222 registerscript("texvar", function()
223 if not expandtex(unknown_value,"mpcategoryparameter",true,scanstring()) then
224 injectnumeric(0)
225 end
226 end)
227
228 registerscript("texstr", function()
229 if not expandtex(string_value,"mpcategoryparameter",true,scanstring()) then
230 injectstring("")
231 end
232 end)
233
234end
235
236do
237
238 registerscript("textextanchor", function()
239 local x, y = match(scanstring(),"tx_anchor=(%S+) (%S+)")
240 if x and y then
241 x = tonumber(x)
242 y = tonumber(y)
243 end
244 injectpair(x or 0,y or 0)
245 end)
246
247end
248
249do
250
251 local mpnamedcolor = attributes.colors.mpnamedcolor
252 local mpprint = mp.aux.print
253
254 mp.mf_named_color = function(str)
255 mpprint(mpnamedcolor(str))
256 end
257
258
259
260
261 registerscript("namedcolor",function() mpprint(mpnamedcolor(scanstring())) end)
262
263end
264
265do
266
267 local hashes = setmetatableindex("table")
268
269
270
271
272 local registry = { }
273 local count = 0
274
275 registerdirect("lmt_hash_new", function()
276 local slot = false
277 for i=1,count do
278 if registry[i] then
279 slot = i
280 break
281 end
282 end
283 if not slot then
284 count = count + 1
285 slot = count
286 end
287 registry[slot] = true
288 hashes[slot] = nil
289 injectwhatever(slot)
290 end)
291
292 registerdirect("lmt_hash_dispose", function()
293 local name = scanwhatever()
294 hashes[name] = nil
295
296 if registry[name] then
297 registry[name] = false
298 end
299 end)
300
301 registerdirect("lmt_hash_reset", function()
302 local name = scanwhatever()
303 hashes[name] = nil
304 end)
305
306 registerdirect("lmt_hash_in", function()
307 local name = scanwhatever()
308 local key = scanwhatever()
309 local hash = hashes[name]
310 injectwhatever(hash and hash[key] and true or false)
311 end)
312
313 registerdirect("lmt_hash_to", function()
314 local name = scanwhatever()
315 local key = scanwhatever()
316 local value = scanwhatever()
317 local hash = hashes[name]
318 if hash then
319 hash[key] = value
320 end
321 end)
322
323 registerdirect("lmt_hash_from", function()
324
325 local name = scanwhatever()
326
327 local key = scanwhatever()
328 local hash = hashes[name]
329 injectwhatever(hash and hash[key] or false)
330 end)
331
332 interfaces.implement {
333 name = "MPfromhash",
334 arguments = "2 strings",
335 actions = function(name,key)
336 local hash = hashes[name] or hashes[tonumber(name)] or hashes[tostring(name)]
337 if hash then
338 local v = hash[key]
339 if v then
340 context(v)
341 end
342 end
343 end
344 }
345
346end
347
348do
349
350 local bpfactor = number.dimenfactors.bp
351 local nbdimensions = nodes.boxes.dimensions
352
353 registerdirect("boxdimensions", function()
354 local category = scanstring()
355 local index = scanwhatever()
356 injectwhd(nbdimensions(category,index))
357 end)
358
359end
360
361do
362
363 local skiptoken = skip.token
364
365 local comma_code <const> = codes.comma
366
367 local getmacro = tokens.getters.macro
368 local setmacro = tokens.setters.macro
369
370 local getdimen = tex.getdimen
371 local getcount = tex.getcount
372 local gettoks = tex.gettoks
373 local setdimen = tex.setdimen
374 local setcount = tex.setcount
375 local settoks = tex.settoks
376
377
378
379 registerdirect("getmacro", function() return getmacro(scanstring()) end)
380 registerdirect("getcount", function() return getcount(scanwhatever()) end)
381 registerdirect("gettoks", function() return gettoks (scanwhatever()) end)
382 registerdirect("getdimen", function() return getdimen(scanwhatever()) * bpfactor end)
383
384 registerscript("setmacro", function() setmacro(scanstring(),scanstring()) end)
385 registerscript("setdimen", function() setdimen(scanwhatever(),scannumeric()/bpfactor) end)
386 registerscript("setcount", function() setcount(scanwhatever(),scannumeric()) end)
387 registerscript("settoks", function() settoks (scanwhatever(),scanstring()) end)
388
389 registerscript("setglobalmacro", function() setmacro(scanstring(),scanstring(),"global") end)
390 registerscript("setglobaldimen", function() setdimen("global",scanwhatever(),scannumeric()/bpfactor) end)
391 registerscript("setglobalcount", function() setcount("global",scanwhatever(),scaninteger()) end)
392 registerscript("setglobaltoks", function() settoks ("global",scanwhatever(),scanstring()) end)
393
394 local utfnum = utf.byte
395 local utfchr = utf.char
396 local utflen = utf.len
397 local utfsub = utf.sub
398
399 registerdirect("utfchr", function() return utfchr(scannumeric()) end)
400 registerdirect("utfnum", function() return utfnum(scanstring()) end)
401 registerdirect("utflen", function() return utflen(scanstring()) end)
402
403 registerdirect("utfsub", function()
404 return utfsub(scanstring(),skiptoken(comma_code) and scannumeric(),skiptoken(comma_code) and scannumeric())
405 end)
406
407 local setlogging = metapost.setlogging
408
409 registerscript("message", function()
410 setlogging(false)
411 local str = scanstring()
412 setlogging(true)
413 report_message("message : %s",str)
414 end)
415
416end
417
418
419
420do
421
422 local getcount = tex.getcount
423
424 local mpprint = mp.print
425 local mpfprint = mp.fprint
426
427 local mpscaninteger = mp.scan.integer
428 local mpscannumber = mp.scan.number
429
430 local jobpositions = job.positions
431 local getwhd = jobpositions.whd
432 local getxy = jobpositions.xy
433 local getx = jobpositions.x
434 local gety = jobpositions.y
435 local getposition = jobpositions.position
436 local getpage = jobpositions.page
437 local getparagraph = jobpositions.paragraph
438 local getregion = jobpositions.region
439 local getcolumn = jobpositions.column
440 local getmacro = tokens.getters.macro
441
442 local columnofpos = jobpositions.columnofpos
443 local getcolumndata = jobpositions.getcolumndata
444
445
446
447
448
449
450 registerscript("positionpath", function()
451 local w, h, d = getwhd(scanstring())
452 if w then
453 mpfprint("((%p,%p)--(%p,%p)--(%p,%p)--(%p,%p)--cycle)",0,-d,w,-d,w,h,0,h)
454 else
455 mpprint("(origin--cycle)")
456 end
457 end)
458
459 registerscript("positioncurve", function()
460 local w, h, d = getwhd(scanstring())
461 if w then
462 mpfprint("((%p,%p)..(%p,%p)..(%p,%p)..(%p,%p)..cycle)",0,-d,w,-d,w,h,0,h)
463 else
464 mpprint("(origin--cycle)")
465 end
466 end)
467
468 registerscript("positionbox", function()
469 local p, x, y, w, h, d = getposition(scanstring())
470 if p then
471 mpfprint("((%p,%p)--(%p,%p)--(%p,%p)--(%p,%p)--cycle)",x,y-d,x+w,y-d,x+w,y+h,x,y+h)
472 else
473 mpprint("(%p,%p)--cycle",x or 0,y or 0)
474 end
475 end)
476
477 registerscript("positioncolumnbox", function()
478 local column = mpscaninteger()
479 local data = getcolumndata(getcount("realpageno"),column)
480 if data then
481 local x, y, w, h, d = data.x, data.y, data.w, data.h, data.d
482 mpfprint("((%p,%p)--(%p,%p)--(%p,%p)--(%p,%p)--cycle)",x,y-d,x+w,y-d,x+w,y+h,x,y+h)
483 else
484 mpprint("(0,0)--cycle")
485 end
486 end)
487
488 registerscript("overlaycolumnbox", function()
489 local column = mpscaninteger()
490 local data = getcolumndata(getcount("realpageno"),column)
491 if data then
492 local w, hd = data.w, data.h + data.d
493 mpfprint("((0,0)--(%p,0)--(%p,%p)--(0,%p)--cycle)",w,w,hd,hd)
494 else
495 mpprint("(0,0)--cycle")
496 end
497 end)
498
499 registerdirect("positionpage", function() return getpage (scanstring()) or 0 end)
500 registerdirect("positioncolumn", function() return getcolumn (scanstring()) or 0 end)
501 registerdirect("positionparagraph", function() return getparagraph(scanstring()) or 0 end)
502 registerdirect("positionregion", function() return getregion (scanstring()) or "unknown" end)
503 registerdirect("positionanchor", function() return getmacro ("MPanchorid") end)
504 registerdirect("positionwhd", function() injectwhd(getwhd(scanstring())) end)
505 registerdirect("positionxy", function() injectxy (getxy (scanstring())) end)
506 registerdirect("positionx", function() injectpt (getx (scanstring())) end)
507 registerdirect("positiony", function() injectpt (gety (scanstring())) end)
508
509 registerdirect("positioncolumnatx", function()
510 local realpage = mpscaninteger()
511 local xposition = mpscannumber()
512 return columnofpos(realpage,xposition)
513 end)
514
515end
516
517do
518
519 local modes = tex.modes
520 local systemmodes = tex.systemmodes
521
522 registerdirect("mode", function() injectboolean(modes [scanstring()] and true or false) end)
523 registerdirect("systemmode", function() injectboolean(systemmodes[scanstring()] and true or false) end)
524
525
526
527 local modes = tex.modes
528 local systemmodes = tex.systemmodes
529
530 function mp.mode(s)
531 injectboolean(modes[s] and true or false)
532 end
533
534 function mp.systemmode(s)
535 injectboolean(systemmodes[s] and true or false)
536 end
537
538 mp.processingmode = mp.mode
539
540end
541
542
543
544do
545
546 local lpegmatch, lpegpatterns, P = lpeg.match, lpeg.patterns, lpeg.P
547
548
549
550 registerdirect("isarray", function()
551 injectboolean(find(scanstring(),"%d") and true or false)
552 end)
553
554 registerdirect("prefix", function()
555 local str = scanstring()
556 return match(str,"^(.-)[%d%[]") or str
557 end)
558
559 local dimension = lpeg.counter(P("[") * lpegpatterns.integer * P("]") + lpegpatterns.integer)
560
561 registerdirect("dimension", function() return dimension(scanstring()) end)
562
563
564
565
566
567
568
569 local p1 = P("mf_object=")
570 local p2 = lpegpatterns.eol * p1
571 local pattern = (1-p2)^0 * p2 + p1
572
573 registerdirect("isobject", function()
574 local str = scanstring()
575 injectboolean(pattern and str ~= "" and lpegmatch(pattern,str))
576 end)
577
578end
579
580
581
582do
583
584 local stack, top = { }, nil
585
586 local function setvariable(k,v)
587 if top then
588 top[k] = v
589 else
590 metapost.variables[k] = v
591 end
592 end
593
594 local function pushvariable(k)
595 local t = { }
596 if top then
597 insert(stack,top)
598 top[k] = t
599 else
600 metapost.variables[k] = t
601 end
602 top = t
603 end
604
605 local function popvariable()
606 top = remove(stack)
607 end
608
609 registerscript("passvariable", function() setvariable (scanstring(), scanwhatever()) end)
610 registerscript("pushvariable", function() pushvariable(scanstring()) end)
611 registerscript("popvariable", function() popvariable () end)
612
613 local stack = { }
614
615 local function pushvariables()
616 insert(stack,metapost.variables)
617 metapost.variables = { }
618 end
619
620 local function popvariables()
621 metapost.variables = remove(stack) or metapost.variables
622 end
623
624 metapost.setvariable = setvariable
625 metapost.pushvariable = pushvariable
626 metapost.popvariable = popvariable
627 metapost.pushvariables = pushvariables
628 metapost.popvariables = popvariables
629
630 implement {
631 name = "mppushvariables",
632 actions = pushvariables,
633 }
634
635 implement {
636 name = "mppopvariables",
637 actions = popvariables,
638 }
639
640end
641
642do
643
644 local repeatable = utilities.randomizer.repeatable
645
646 registerdirect("repeatablerandom", function()
647 return repeatable(scanstring())
648 end)
649
650end
651
652do
653
654 local hascurvature = metapost.hascurvature
655
656 registerdirect("hascurvature",
657 function()
658 local p = scanpath()
659 local t = scannumeric()
660 local l = p[1]
661 local r = p[#p]
662 injectboolean(l and r and hascurvature (
663 {
664 x_coord = l[1], y_coord = l[2],
665 left_x = l[3], left_y = l[4],
666 right_x = l[5], right_y = l[6],
667 }, {
668 x_coord = r[1], y_coord = r[2],
669 left_x = r[3], left_y = r[4],
670 right_x = r[5], right_y = r[6],
671 },
672 t
673 ) or false)
674 end
675 )
676
677end
678
679do
680
681 local defaults = {
682 noplugins = false
683 }
684
685 local backendoptions = setmetatableindex(function(t,k) local v = setmetatable({},defaults) t[k] = v return v end)
686
687 function metapost.resetbackendoptions(mpx)
688 backendoptions[mpx] = setmetatable({},defaults)
689 end
690
691 function metapost.getbackendoption(mpx,name)
692 return backendoptions[mpx][name]
693 end
694
695 registerdirect("setbackendoption",
696 function()
697 backendoptions[metapost.currentmpx()][scanstring()] = true
698 end
699 )
700end
701
702do
703
704 registerdirect("namedstacking", function()
705 injectnumeric(typesetters.stacking.getindex(scanstring()))
706 end)
707
708end
709 |