1 if not modules then modules = { } end modules ['syst-aux'] = {
2 version = 1.001,
3 comment = "companion to syst-aux.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
11
12
13
14local tonumber, next, type = tonumber, next, type
15local utfsub = utf.sub
16local P, S, R, C, Cc, Cs, Carg, lpegmatch = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Carg, lpeg.match
17local find, formatters = string.find, string.formatters
18
19local context = context
20local implement = interfaces.implement
21local setmacro = interfaces.setmacro
22local setcatcode = tex.setcatcode
23local texget = tex.get
24local utf8character = lpeg.patterns.utf8character
25local settings_to_array = utilities.parsers.settings_to_array
26local settings_to_set = utilities.parsers.settings_to_set
27
28local pattern = C(utf8character^-1) * C(P(1)^0)
29
30implement {
31 name = "getfirstcharacter",
32 arguments = "string",
33 actions = function(str)
34 local first, rest = lpegmatch(pattern,str)
35 setmacro("firstcharacter",first)
36 setmacro("remainingcharacters",rest)
37 end
38}
39
40implement {
41 name = "thefirstcharacter",
42 arguments = "string",
43 actions = function(str)
44 local first, rest = lpegmatch(pattern,str)
45 context(first)
46 end
47}
48
49implement {
50 name = "theremainingcharacters",
51 arguments = "string",
52 actions = function(str)
53 local first, rest = lpegmatch(pattern,str)
54 context(rest)
55 end
56}
57
58local pattern = C(utf8character^-1)
59local ctx_doifelse = commands.doifelse
60
61implement {
62 name = "doifelsefirstchar",
63 arguments = "2 strings",
64 actions = function(str,chr)
65 ctx_doifelse(lpegmatch(pattern,str) == chr)
66 end
67}
68
69implement {
70 name = "getsubstring",
71 arguments = "3 strings",
72 actions = function(str,first,last)
73 context(utfsub(str,tonumber(first),tonumber(last)))
74 end
75}
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107local pattern = (C((1-P("%"))^1) * Carg(1)) / function(n,d)
108 return formatters["%.0fsp"](d * tonumber(n)/100) end * P("%") * P(-1)
109
110
111
112implement {
113 name = "percentageof",
114 arguments = { "string", "dimen" },
115 actions = function(str,dim)
116 context(lpegmatch(pattern,str,1,dim) or str)
117 end
118}
119
120
121
122
123local space = P(" ") / ""
124local spaces = P(" ")^0 / ""
125local nohash = 1 - P("#")
126local digit = R("09")
127local double = P("##") / "#"
128local single = P("#")
129local sentinel = spaces * (nohash^1 / "\\%0")
130local sargument = (single * digit)^1
131local dargument = (double * digit)^1
132
133
134
135local global = nil
136local protected = nil
137local expanded = nil
138local optional = nil
139local csname = nil
140local rest = nil
141
142local function catcodes_s()
143 setcatcode(32,10)
144 setcatcode(13, 5)
145end
146
147local function catcodes_n()
148 setcatcode(32, 9)
149 setcatcode(13, 9)
150end
151
152local space = P(" ")
153local spaces = space^0
154
155local option = (
156 P("single")
157 + P("double")
158 + P("triple")
159 + P("quadruple")
160 + P("quintuple")
161 + P("sixtuple")
162 ) * (P("empty") + P("argument"))
163
164local pattern = (
165 (
166 spaces * (
167 ( P("spaces") * space / catcodes_s )
168 + ( P("nospaces") * space / catcodes_n )
169 + ( P("global") * space / function() global = true end )
170 + ( P("protected") * space / function() protected = true end)
171 + ( P("permanent") * space )
172 + ( P("expanded") * space / function() expanded = true end)
173 + ( P("tolerant") * space )
174 + ( P("instance") * space )
175 + ( P("frozen") * space )
176 + ( P("mutable") * space )
177 + ( P("immutable") * space )
178 + ( P("unexpanded") * space / function() protected = true end)
179 + ( C(option) * space / function(s) optional = s end)
180 )
181 )^0
182 * spaces * ( C((1-S(" #["))^1) )
183 * spaces * Cs(
184 ( P("[") * dargument * P("]") + dargument)^1 * sentinel^-1 * double^-1
185 + ( P("[") * sargument * P("]") + sargument)^1 * sentinel^-1 * single^-1
186 + sentinel^-1 * (double+single)^-1
187 )
188)
189
190local ctx_dostarttexdefinition = context.dostarttexdefinition
191
192local function texdefinition_one(str)
193 global = false
194 protected = false
195 expanded = false
196 optional = false
197 csname, rest = lpegmatch(pattern,str)
198 ctx_dostarttexdefinition()
199end
200
201local function texdefinition_two()
202 if optional then
203 context (
204 (protected and [[\protected]] or "") ..
205 [[\expandafter]] .. (global and [[\xdef]] or [[\edef]]) ..
206 [[\csname ]] .. csname .. [[\endcsname{\expandafter\noexpand\expandafter\do]] .. optional ..
207 [[\csname _do_]] .. csname .. [[_\endcsname}\expandafter]] .. (global and [[\gdef]] or [[\edef]]) ..
208 [[\csname _do_]] .. csname .. [[_\endcsname ]] ..
209 rest
210 )
211 else
212 context (
213 (protected and [[\protected]] or "") ..
214 [[\expandafter]] .. (global and (expanded and [[\xdef]] or [[\gdef]]) or (expanded and [[\edef]] or [[\def]])) ..
215 [[\csname ]] .. csname .. [[\endcsname ]] ..
216 rest
217 )
218 end
219end
220
221implement { name = "texdefinition_one", actions = texdefinition_one, scope = "private", arguments = "string" }
222implement { name = "texdefinition_two", actions = texdefinition_two, scope = "private" }
223
224do
225
226
227
228
229 local _lower_, _upper_, _strip_
230
231 _lower_ = function(s)
232 if characters and characters.lower then
233 _lower_ = characters.lower
234 return _lower_(s)
235 end
236 return string.lower(s)
237 end
238
239 _upper_ = function(s)
240 if characters and characters.upper then
241 _upper_ = characters.upper
242 return _upper_(s)
243 end
244 return string.upper(s)
245 end
246
247 _strip_ = function(s)
248
249 if string.strip then
250 _strip_ = string.strip
251 return _strip_(s)
252 end
253 return s
254 end
255
256 local function lower(s) context(_lower_(s)) end
257 local function upper(s) context(_upper_(s)) end
258 local function strip(s) context(_strip_(s)) end
259
260 implement { name = "upper", arguments = "string", actions = upper }
261 implement { name = "lower", arguments = "string", actions = lower }
262 implement { name = "strip", arguments = "string", actions = strip }
263
264end
265
266implement {
267 name = "converteddimen",
268 arguments = { "dimen", "string" },
269 actions = function(dimen,unit)
270 context(number.todimen(dimen,unit or "pt","%0.5f"))
271 end
272}
273
274
275
276implement {
277 name = "immediatemessage",
278 arguments = { "'message'", "string" },
279 actions = logs.status
280}
281
282implement {
283 name = "resettimer",
284 actions = function()
285 statistics.resettiming("whatever")
286 statistics.starttiming("whatever")
287 end
288}
289
290implement {
291 name = "benchmarktimer",
292 actions = function()
293 statistics.benchmarktimer("whatever")
294 end
295}
296
297implement {
298 name = "elapsedtime",
299 actions = function()
300 statistics.stoptiming("whatever")
301 context(statistics.elapsedtime("whatever"))
302 end
303}
304
305implement {
306 name = "elapsedsteptime",
307 arguments = "integer",
308 actions = function(n)
309 statistics.stoptiming("whatever")
310 local t = statistics.elapsed("whatever")/(n > 0 and n or 1)
311 if t > 0 then
312 context("%0.9f",t)
313 else
314 context(0)
315 end
316 end
317}
318
319local accuracy = table.setmetatableindex(function(t,k)
320 local v = formatters["%0." ..k .. "f"]
321 t[k] = v
322 return v
323end)
324
325implement {
326 name = "rounded",
327 arguments = "integer",
328 actions = function(n,m) context(accuracy[n](m)) end
329}
330
331
332
333local ctx_protected_cs = context.protected.cs
334
335local ctx_firstoftwoarguments = ctx_protected_cs.firstoftwoarguments
336local ctx_secondoftwoarguments = ctx_protected_cs.secondoftwoarguments
337local ctx_firstofoneargument = ctx_protected_cs.firstofoneargument
338local ctx_gobbleoneargument = ctx_protected_cs.gobbleoneargument
339
340context.firstoftwoarguments = ctx_firstoftwoarguments
341context.secondoftwoarguments = ctx_secondoftwoarguments
342context.firstofoneargument = ctx_firstofoneargument
343context.gobbleoneargument = ctx_gobbleoneargument
344
345local ctx_iftrue = context.iftrue
346local ctx_iffalse = context.iffalse
347
348local hash = utilities.parsers.hashes.settings_to_set
349
350local function doifelsecommon(a,b)
351 if a == b then
352 setmacro("commalistelement",a)
353 if a == "" then
354 ctx_secondoftwoarguments()
355 else
356 ctx_firstoftwoarguments()
357 end
358 return
359 end
360 local ba = find(a,",",1,true)
361 local bb = find(b,",",1,true)
362 if ba and bb then
363 local ha = hash[a]
364 local hb = hash[b]
365
366
367 for k in next, ha do
368 if hb[k] then
369 setmacro("commalistelement",k)
370 ctx_firstoftwoarguments()
371 return
372 end
373 end
374 elseif ba then
375 if hash[a][b] then
376
377 setmacro("commalistelement",b)
378 ctx_firstoftwoarguments()
379 return
380 end
381 elseif bb then
382 if hash[b][a] then
383
384 setmacro("commalistelement",a)
385 ctx_firstoftwoarguments()
386 return
387 end
388 end
389 setmacro("commalistelement","")
390 ctx_secondoftwoarguments()
391end
392
393local function doifcommon(a,b)
394 if a == b then
395 setmacro("commalistelement",a)
396 if a == "" then
397 ctx_gobbleoneargument()
398 else
399 ctx_firstofoneargument()
400 end
401 return
402 end
403 local ba = find(a,",",1,true)
404 local bb = find(b,",",1,true)
405 if ba and bb then
406 local ha = hash[a]
407 local hb = hash[b]
408
409
410 for k in next, ha do
411 if hb[k] then
412 setmacro("commalistelement",k)
413 ctx_firstofoneargument()
414 return
415 end
416 end
417 elseif ba then
418 if hash[a][b] then
419
420 setmacro("commalistelement",b)
421 ctx_firstofoneargument()
422 return
423 end
424 elseif bb then
425 if hash[b][a] then
426
427 setmacro("commalistelement",a)
428 ctx_firstofoneargument()
429 return
430 end
431 end
432 setmacro("commalistelement","")
433 ctx_gobbleoneargument()
434end
435
436local function doifnotcommon(a,b)
437 if a == b then
438 setmacro("commalistelement",a)
439 if a == "" then
440 ctx_firstofoneargument()
441 else
442 ctx_gobbleoneargument()
443 end
444 return
445 end
446 local ba = find(a,",",1,true)
447 local bb = find(b,",",1,true)
448 if ba and bb then
449 local ha = hash[a]
450 local hb = hash[b]
451
452
453 for k in next, ha do
454 if hb[k] then
455 setmacro("commalistelement",k)
456 ctx_gobbleoneargument()
457 return
458 end
459 end
460 elseif ba then
461 if hash[a][b] then
462
463 setmacro("commalistelement",b)
464 ctx_gobbleoneargument()
465 return
466 end
467 elseif bb then
468 if hash[b][a] then
469
470 setmacro("commalistelement",a)
471 ctx_gobbleoneargument()
472 return
473 end
474 end
475 setmacro("commalistelement","")
476 ctx_firstofoneargument()
477end
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518local function doifelseinset(a,b)
519 if a == b then
520 setmacro("commalistelement",a)
521 if a == "" then
522 ctx_secondoftwoarguments()
523 else
524 ctx_firstoftwoarguments()
525 end
526 return
527 end
528 local bb = find(b,",",1,true)
529 if bb then
530 if hash[b][a] then
531
532 setmacro("commalistelement",a)
533 ctx_firstoftwoarguments()
534 return
535 end
536 end
537 setmacro("commalistelement","")
538 ctx_secondoftwoarguments()
539end
540
541local function doifinset(a,b)
542 if a == b then
543 setmacro("commalistelement",a)
544 if a == "" then
545 ctx_gobbleoneargument()
546 else
547 ctx_firstofoneargument()
548 end
549 return
550 end
551 local bb = find(b,",",1,true)
552 if bb then
553 if hash[b][a] then
554
555 setmacro("commalistelement",a)
556 ctx_firstofoneargument()
557 return
558 end
559 end
560 setmacro("commalistelement","")
561 ctx_gobbleoneargument()
562end
563
564local function doifnotinset(a,b)
565 if a == b then
566 setmacro("commalistelement",a)
567 if a == "" then
568 ctx_firstofoneargument()
569 else
570 ctx_gobbleoneargument()
571 end
572 return
573 end
574 local bb = find(b,",",1,true)
575 if bb then
576 if hash[b][a] then
577
578 setmacro("commalistelement",a)
579 ctx_gobbleoneargument()
580 return
581 end
582 end
583 setmacro("commalistelement","")
584 ctx_firstofoneargument()
585end
586
587implement {
588 name = "doifelsecommon",
589 actions = doifelsecommon,
590 arguments = "2 strings",
591}
592
593implement {
594 name = "doifcommon",
595 actions = doifcommon,
596 arguments = "2 strings",
597}
598
599implement {
600 name = "doifnotcommon",
601 actions = doifnotcommon,
602 arguments = "2 strings",
603}
604
605
606
607
608
609
610
611
612implement {
613 name = "doifelseinset",
614 actions = doifelseinset,
615 arguments = "2 strings",
616
617}
618
619implement {
620 name = "doifinset",
621 actions = doifinset,
622 arguments = "2 strings",
623}
624
625implement {
626 name = "doifnotinset",
627 actions = doifnotinset,
628 arguments = "2 strings",
629}
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684local bp = number.dimenfactors.bp
685
686implement {
687 name = "tobigpoints",
688 actions = function(d) context("%.5F",bp * d) end,
689 arguments = "dimension",
690}
691
692implement {
693 name = "towholebigpoints",
694 actions = function(d) context("%r",bp * d) end,
695 arguments = "dimension",
696}
697
698
699
700local function getshape(s)
701 local t = texget(s)
702 local n = t and #t or 0
703 context(n)
704 if n > 0 then
705 for i=1,n do
706 local ti = t[i]
707 if type(ti) == "table" then
708 context(" %isp %isp",ti[1],ti[2])
709 else
710 context(" %i",ti)
711 end
712 end
713 end
714end
715
716implement {
717 name = "getparshape",
718 public = true,
719 actions = function() getshape("parshape") end,
720}
721implement {
722 name = "getclubpenalties",
723 public = true,
724 actions = function() getshape("clubpenalties") end,
725}
726implement {
727 name = "getinterlinepenalties",
728 public = true,
729 actions = function() getshape("interlinepenalties") end,
730 }
731implement {
732 name = "getdisplaywidowpenalties",
733 public = true,
734 actions = function() getshape("displaywidowpenalties") end,
735}
736implement {
737 name = "getwidowpenalties",
738 public = true,
739 actions = function() getshape("widowpenalties") end,
740}
741 |