node-tsk.lua /size: 16 Kb    last modification: 2021-10-28 13:50
1if not modules then modules = { } end modules ['node-tsk'] = {
2    version   = 1.001,
3    comment   = "companion to node-ini.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-- This might move to task-* and become less code as in sequencers
10-- we already have dirty flags as well. On the other hand, nodes are
11-- rather specialized and here we focus on node related tasks.
12
13local format = string.format
14
15local trace_tasks = false  trackers.register("tasks.creation", function(v) trace_tasks = v end)
16
17local report_tasks  = logs.reporter("tasks")
18
19local allocate      = utilities.storage.allocate
20
21local context       = context
22local nodes         = nodes
23
24local tasks         = nodes.tasks or { }
25nodes.tasks         = tasks
26
27local tasksdata     = { } -- no longer public
28
29local sequencers    = utilities.sequencers
30local compile       = sequencers.compile
31local nodeprocessor = sequencers.nodeprocessor
32
33local newsequencer  = sequencers.new
34
35local appendgroup   = sequencers.appendgroup
36----- prependgroup  = sequencers.prependgroup
37----- replacegroup  = sequencers.replacegroup
38local enablegroup   = sequencers.enablegroup
39local disablegroup  = sequencers.disablegroup
40
41local appendaction  = sequencers.appendaction
42local prependaction = sequencers.prependaction
43local replaceaction = sequencers.replaceaction
44local enableaction  = sequencers.enableaction
45local disableaction = sequencers.disableaction
46
47local frozengroups  = "no"
48
49function tasks.freeze(kind)
50    frozengroups = kind or "tolerant" -- todo: hook into jobname
51end
52
53function tasks.new(specification) -- was: name,arguments,list
54    local name      = specification.name
55    local sequence  = specification.sequence
56    if name and sequence then
57        local tasklist = newsequencer {
58            name = name
59            -- we can move more to the sequencer now .. todo
60        }
61        tasksdata[name] = {
62            name      = name,
63            list      = tasklist,
64            runner    = false,
65            frozen    = { },
66            processor = specification.processor or nodeprocessor,
67            -- could be metatable but best freeze it
68            arguments = specification.arguments or 0,
69            templates = specification.templates,
70        }
71        for l=1,#sequence do
72            appendgroup(tasklist,sequence[l])
73        end
74    end
75end
76
77local function valid(name)
78    local data = tasksdata[name]
79    if not data then
80        report_tasks("unknown task %a",name)
81    else
82        return data
83    end
84end
85
86local function validgroup(name,group,what)
87    local data = tasksdata[name]
88    if not data then
89        report_tasks("unknown task %a",name)
90    else
91        local frozen = data.frozen[group]
92        if frozen then
93            if frozengroup == "no" then
94                -- default
95            elseif frozengroup == "strict" then
96                report_tasks("warning: group %a of task %a is frozen, %a applied but not supported",group,name,what)
97                return
98            else -- if frozengroup == "tolerant" then
99                report_tasks("warning: group %a of task %a is frozen, %a ignored",group,name,what)
100            end
101        end
102        return data
103    end
104end
105
106function tasks.freezegroup(name,group)
107    local data = valid(name)
108    if data then
109        data.frozen[group] = true
110    end
111end
112
113function tasks.restart(name)
114    local data = valid(name)
115    if data then
116        data.runner = false
117    end
118end
119
120function tasks.enableaction(name,action)
121    local data = valid(name)
122    if data then
123        enableaction(data.list,action)
124        data.runner = false
125    end
126end
127
128function tasks.disableaction(name,action)
129    local data = valid(name)
130    if data then
131        disableaction(data.list,action)
132        data.runner = false
133    end
134end
135
136function tasks.replaceaction(name,group,oldaction,newaction)
137    local data = valid(name)
138    if data then
139        replaceaction(data.list,group,oldaction,newaction)
140        data.runner = false
141    end
142end
143
144do
145
146    local enableaction  = tasks.enableaction
147    local disableaction = tasks.disableaction
148
149    function tasks.setaction(name,action,value)
150        if value then
151            enableaction(name,action)
152        else
153            disableaction(name,action)
154        end
155    end
156
157end
158
159function tasks.enablegroup(name,group)
160    local data = validgroup(name,"enable group")
161    if data then
162        enablegroup(data.list,group)
163        data.runner = false
164    end
165end
166
167function tasks.disablegroup(name,group)
168    local data = validgroup(name,"disable group")
169    if data then
170        disablegroup(data.list,group)
171        data.runner = false
172    end
173end
174
175function tasks.appendaction(name,group,action,where,kind,state)
176    local data = validgroup(name,"append action")
177    if data then
178        local list = data.list
179        appendaction(list,group,action,where,kind)
180        if state == "disabled" or (state == "production" and environment.initex) then
181            disableaction(list,action)
182        end
183        data.runner = false
184    end
185end
186
187function tasks.prependaction(name,group,action,where,kind,state)
188    local data = validgroup(name,"prepend action")
189    if data then
190        local list = data.list
191        prependaction(list,group,action,where,kind)
192        if state == "disabled" or (state == "production" and environment.initex) then
193            disableaction(list,action)
194        end
195        data.runner = false
196    end
197end
198
199function tasks.removeaction(name,group,action)
200    local data = validgroup(name,"remove action")
201    if data then
202        removeaction(data.list,group,action)
203        data.runner = false
204    end
205end
206
207function tasks.showactions(name,group,action,where,kind)
208    local data = valid(name)
209    if data then
210        report_tasks("task %a, list:\n%s",name,nodeprocessor(data.list))
211    end
212end
213
214-- Optimizing for the number of arguments makes sense, but getting rid of
215-- the nested call (no problem but then we also need to register the
216-- callback with this mechanism so that it gets updated) does not save
217-- much time (24K calls on mk.tex).
218
219local created, total = 0, 0
220
221statistics.register("node list callback tasks", function()
222    if total > 0 then
223        return format("%s unique task lists, %s instances (re)created, %s calls",table.count(tasksdata),created,total)
224    else
225        return nil
226    end
227end)
228
229local function create(data,t)
230    created = created + 1
231    local runner = compile(data.list,data.processor,t)
232    if trace_tasks then
233        report_tasks("creating runner %a, %i actions enabled",t.name,data.list.steps or 0)
234    end
235    data.runner = runner
236    return runner
237end
238
239function tasks.actions(name)
240    local data = tasksdata[name]
241    if data then
242        local t = data.templates
243        if t then
244            t.name = data.name
245            return function(...)
246                total = total + 1
247                return (data.runner or create(data,t))(...)
248            end
249        end
250    end
251    return nil
252end
253
254function tasks.table(name) --maybe move this to task-deb.lua
255    local tsk = tasksdata[name]
256    local lst = tsk and tsk.list
257    local HL, NC, NR, bold, type = context.HL, context.NC, context.NR, context.bold, context.type
258    if lst then
259        local list, order = lst.list, lst.order
260        if list and order then
261            context.starttabulate { "|l|l|" }
262            NC() bold("category") NC() bold("function") NC() NR()
263            for i=1,#order do
264                HL()
265                local o = order[i]
266                local l = list[o]
267                if #l == 0 then
268                    NC() type(o) NC() context("unset") NC() NR()
269                else
270                    local done = false
271                    for k, v in table.sortedhash(l) do
272                        NC() if not done then type(o) done = true end NC() type(v) NC() NR()
273                    end
274                end
275            end
276            context.stoptabulate()
277        end
278    end
279end
280
281-- -- shipouts everypar -- --
282
283-- the shipout handlers acts on boxes so we don't need to return something
284-- and also don't need to keep the state (done)
285
286local templates = {
287
288default = [[
289return function(head)
290    return head
291end
292]],
293
294process = [[
295local tonut  = nodes.tonut
296local tonode = nodes.nuts.tonode
297
298%localize%
299
300return function(head)
301    local nuthead = tonut(head)
302
303%actions%
304    return tonode(nuthead)
305end
306]],
307
308step = [[
309    nuthead = tonut((%action%(tonode(nuthead))))
310]],
311
312nut  = [[
313    nuthead = %action%(nuthead)
314]],
315
316nohead = [[
317    %action%(tonode(nuthead))
318]],
319
320nonut = [[
321    %action%(nuthead)
322]],
323
324}
325
326tasks.new {
327    name      = "shipouts",
328    processor = nodeprocessor,
329    sequence  = {
330        "before",      -- users
331        "normalizers", -- system
332        "finishers",   -- system
333        "after",       -- users
334        "wrapup",      -- system
335    },
336    templates = templates
337}
338
339tasks.new {
340    name      = "everypar",
341    processor = nodeprocessor,
342    sequence  = {
343        "before",      -- users
344        "normalizers", -- system
345        "after",       -- users
346    },
347    templates = templates,
348}
349
350-- -- finalizers -- --
351
352tasks.new {
353    name      = "finalizers",
354    sequence  = {
355        "before",      -- for users
356        "normalizers",
357        "fonts",
358        "lists",
359        "after",       -- for users
360    },
361    processor = nodeprocessor,
362    templates = {
363
364default = [[
365return function(head)
366    return head
367end
368]],
369
370process = [[
371local tonut  = nodes.tonut
372local tonode = nodes.nuts.tonode
373
374%localize%
375
376return function(head,groupcode)
377    local nuthead = tonut(head)
378
379%actions%
380    return tonode(nuthead)
381end
382]],
383
384step = [[
385    nuthead = tonut((%action%(tonode(nuthead),groupcode)))
386]],
387
388nut  = [[
389    nuthead = %action%(nuthead,groupcode)
390]],
391
392nohead = [[
393    %action%(tonode(nuthead),groupcode)
394]],
395
396nonut = [[
397    %action%(nuthead,groupcode)
398]],
399
400    }
401}
402
403-- -- processors -- --
404
405tasks.new {
406    name      = "processors",
407    processor = nodeprocessor,
408    sequence  = {
409        "before",      -- for users
410        "normalizers",
411        "characters",
412        "words",
413        "fonts",
414        "lists",
415        "after",       -- for users
416    },
417    templates = {
418
419default = [[
420return function(head)
421    return head
422end
423]],
424
425process = [[
426local tonut  = nodes.tonut
427local tonode = nodes.nuts.tonode
428
429%localize%
430
431return function(head,groupcode,size,packtype,direction,attributes)
432    local nuthead = tonut(head)
433
434%actions%
435    return tonode(nuthead)
436end
437]],
438
439step = [[
440    nuthead = tonut((%action%(tonode(nuthead),groupcode,size,packtype,direction,attributes)))
441]],
442
443nut  = [[
444    nuthead = %action%(nuthead,groupcode,size,packtype,direction,attributes)
445]],
446
447nohead = [[
448    %action%(tonode(nuthead),groupcode,size,packtype,direction,attributes)
449]],
450
451nonut = [[
452    %action%(nuthead,groupcode,size,packtype,direction,attributes)
453]],
454
455    }
456}
457
458tasks.new {
459    name      = "finalizers",
460    processor = nodeprocessor,
461    sequence  = {
462        "before",      -- for users
463        "normalizers",
464        "fonts",
465        "lists",
466        "after",       -- for users
467    },
468    templates = {
469
470default = [[
471return function(head)
472    return head
473end
474]],
475
476process = [[
477local tonut  = nodes.tonut
478local tonode = nodes.nuts.tonode
479
480%localize%
481
482return function(head)
483    local nuthead = tonut(head)
484
485%actions%
486    return tonode(nuthead)
487end
488]],
489
490step = [[
491    nuthead = tonut((%action%(tonode(nuthead))))
492]],
493
494nut  = [[
495    nuthead = %action%(nuthead)
496]],
497
498nohead = [[
499    %action%(tonode(nuthead))
500]],
501
502nonut = [[
503    %action%(nuthead)
504]],
505
506    }
507}
508
509tasks.new {
510    name      = "mvlbuilders",
511    processor = nodeprocessor,
512    sequence  = {
513        "before",      -- for users
514        "normalizers",
515        "after",       -- for users
516    },
517    templates = {
518
519default = [[
520return function(head)
521    return head
522end
523]],
524
525process = [[
526local tonut  = nodes.tonut
527local tonode = nodes.nuts.tonode
528
529%localize%
530
531return function(head,groupcode)
532    local nuthead = tonut(head)
533
534%actions%
535    return tonode(nuthead)
536end
537]],
538
539step = [[
540    nuthead = tonut((%action%(tonode(nuthead),groupcode)))
541]],
542
543nut  = [[
544    nuthead = %action%(nuthead,groupcode)
545]],
546
547nohead = [[
548    %action%(tonode(nuthead),groupcode)
549]],
550
551nonut = [[
552    %action%(nuthead,groupcode)
553]],
554
555    }
556}
557
558tasks.new {
559    name      = "vboxbuilders",
560    processor = nodeprocessor,
561    sequence  = {
562        "before",      -- for users
563        "normalizers",
564        "after",       -- for users
565    },
566    templates = {
567
568default = [[
569return function(head)
570    return head
571end
572]],
573
574process = [[
575local tonut  = nodes.tonut
576local tonode = nodes.nuts.tonode
577
578%localize%
579
580return function(head,groupcode,size,packtype,maxdepth,direction)
581    local nuthead = tonut(head)
582
583%actions%
584    return tonode(nuthead)
585end
586]],
587
588step = [[
589    nuthead = tonut((%action%(tonode(nuthead),groupcode,size,packtype,maxdepth,direction)))
590]],
591
592nut  = [[
593    nuthead = %action%(nuthead,groupcode,size,packtype,maxdepth,direction)
594]],
595
596nohead = [[
597    %action%(tonode(nuthead),groupcode,size,packtype,maxdepth,direction)
598]],
599
600nonut = [[
601    %action%(nuthead,groupcode,size,packtype,maxdepth,direction)
602]],
603
604    }
605
606}
607
608tasks.new {
609    name      = "contributers",
610    processor = nodeprocessor,
611    sequence  = {
612        "before",      -- for users
613        "normalizers",
614        "after",       -- for users
615    },
616    templates = {
617
618default = [[
619return function(head)
620    return head
621end
622]],
623
624process = [[
625local tonut  = nodes.tonut
626local tonode = nodes.nuts.tonode
627
628%localize%
629
630-- we operate exclusively on nuts
631
632return function(nuthead,groupcode,nutline)
633%actions%
634    return nuthead
635end
636]],
637
638step = [[
639    nuthead = tonut((%action%(tonode(nuthead),groupcode,line)))
640]],
641
642nut  = [[
643    nuthead = %action%(nuthead,groupcode,nutline)
644]],
645
646nohead = [[
647    %action%(tonode(nuthead),groupcode,line)
648]],
649
650nonut = [[
651    %action%(nuthead,groupcode,nutline)
652]],
653
654    }
655}
656
657-- -- math -- --
658
659tasks.new {
660    name      = "math",
661    processor = nodeprocessor,
662    sequence  = {
663        "before",
664        "normalizers",
665        "builders",
666        "finalizers",
667        "after",
668    },
669    templates = {
670
671default = [[
672return function(head)
673    return head
674end
675]],
676
677process = [[
678local tonut  = nodes.tonut
679local tonode = nodes.nuts.tonode
680
681%localize%
682
683return function(head,style,penalties)
684    local nuthead = tonut(head)
685
686%actions%
687    return tonode(nuthead)
688end
689]],
690
691step = [[
692    nuthead = tonut((%action%(tonode(nuthead),style,penalties)))
693]],
694
695nut  = [[
696    nuthead = %action%(nuthead,style,penalties)
697]],
698
699nohead = [[
700    %action%(tonode(nuthead),style,penalties)
701]],
702
703nonut = [[
704    %action%(nuthead,style,penalties)
705]],
706
707    }
708}
709
710-- tasks.new {
711--     name      = "parbuilders",
712--     arguments = 1,
713--     processor = nodeprocessor,
714--     sequence  = {
715--         "before",      -- for users
716--         "lists",
717--         "after",       -- for users
718--     }
719-- }
720
721-- tasks.new {
722--     name      = "pagebuilders",
723--     arguments = 5,
724--     processor = nodeprocessor,
725--     sequence  = {
726--         "before",      -- for users
727--         "lists",
728--         "after",       -- for users
729--     }
730-- }
731
732-- for now quite useless (too fuzzy)
733--
734-- tasks.new {
735--     name            = "listbuilders",
736--     processor       = nodeprocessor,
737--     sequence        = {
738--         "before",      -- for users
739--         "normalizers",
740--         "after",       -- for users
741--     },
742--     templates       = {
743-- -- we don't need a default
744--         default = [[
745-- return function(box,location,prevdepth)
746--     return box, prevdepth
747-- end
748--         ]],
749--         process = [[
750-- %localize%
751-- return function(box,location,prevdepth,mirrored)
752--     %actions%
753--     return box, prevdepth
754-- end
755--         ]],
756--         step = [[
757-- box, prevdepth = %action%(box,location,prevdepth,mirrored)
758--         ]],
759--     },
760-- }
761
762-- -- math -- --
763
764-- not really a node processor
765
766-- tasks.new {
767--     name      = "newpar",
768--     processor = nodeprocessor,
769--     sequence  = {
770--         "before",
771--         "normalizers",
772--         "after",
773--     },
774--     templates = {
775--
776-- default = [[
777-- return function(mode,indent)
778--     return indent
779-- end
780-- ]],
781--
782-- process = [[
783-- %localize%
784--
785-- return function(mode,indent)
786--
787-- %actions%
788--     return indent
789-- end
790-- ]],
791--
792-- step = [[
793--     indent = %action%(mode,indent)
794-- ]],
795--
796--     }
797-- }
798