m-nodechart.lua /size: 5899 b    last modification: 2021-10-28 13:51
1if not modules then modules = { } end modules ['m-nodechart'] = {
2    version   = 1.001,
3    comment   = "companion to m-nodechart.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 format       = string.format
10local points       = number.nopts
11local ptfactor     = number.dimenfactors.pt
12
13local nodecodes    = nodes.nodecodes
14local kerncodes    = nodes.kerncodes
15local penaltycodes = nodes.penaltycodes
16local gluecodes    = nodes.gluecodes
17local whatsitcodes = nodes.whatsitcodes
18
19moduledata.charts       = moduledata.charts       or { }
20moduledata.charts.nodes = moduledata.charts.nodes or { }
21
22local formatters = { }
23
24-- subtype font char lang left right uchyph components xoffset yoffset width height depth
25
26function formatters.glyph(n,comment)
27    return format("\\doFLOWglyphnode{%s}{%s}{%s}{%s}{U+%05X}",comment,n.subtype,n.font,n.char,n.char)
28end
29
30-- pre post replace
31
32function formatters.disc(n,comment)
33    return format("\\doFLOWdiscnode{%s}{%s}",comment,n.subtype)
34end
35
36-- subtype kern
37
38function formatters.kern(n,comment)
39 -- return format("\\doFLOWkernnode{%s}{%s}{%s}",comment,kerncodes[n.subtype],points(n.kern))
40    return format("\\doFLOWkernnode{%s}{%s}{%.4f}",comment,kerncodes[n.subtype],n.kern*ptfactor)
41end
42
43-- subtype penalty
44
45function formatters.penalty(n,comment)
46    return format("\\doFLOWpenaltynode{%s}{%s}{%s}",comment,"penalty",n.penalty)
47end
48
49-- subtype width leader spec (stretch shrink ...
50
51function formatters.glue(n,comment)
52    return format("\\doFLOWgluenode{%s}{%s}{%.4f}{%.4f}{%.4f}",comment,gluecodes[n.subtype],n.width*ptfactor,n.stretch*ptfactor,n.shrink*ptfactor)
53end
54
55-- subtype width leader spec (stretch shrink ...
56
57function formatters.whatsit(n,comment)
58    return whatsitcodes[n.id] or "unknown whatsit"
59end
60
61function formatters.dir(n,comment)
62    return format("\\doFLOWdirnode{%s}{%s}{%s}",comment,"dir",n.dir)
63end
64
65function formatters.par(n,comment)
66    return format("\\doFLOWdirnode{%s}{%s}{%s}",comment,"par",n.dir)
67end
68
69-- I will make a dedicated set of shapes for this.
70
71local shapes = {
72    glyph   = "procedure",
73    disc    = "procedure",
74    kern    = "action",
75    penalty = "action",
76    glue    = "action",
77}
78
79local function flow_nodes_to_chart(specification)
80    local head    = specification.head
81    local box     = specification.box
82    local comment = specification.comment or ""
83    local x       = specification.x or 1
84    local y       = specification.y or 0
85    --
86    if box then
87          box  = tex.getbox(tonumber(box))
88          head = box and box.list
89    end
90    --
91    local current = head
92    --
93    while current do
94        local nodecode  = nodecodes[current.id]
95        local formatter = formatters[nodecode]
96        local shape     = shapes[nodecode]
97        y = y + 1
98        local next = current.next
99        commands.flow_start_cell { shape = { framecolor = "nodechart:" .. nodecode } }
100        commands.flow_set_name(tostring(current))
101        commands.flow_set_location(x,y)
102        if shape then
103            commands.flow_set_shape(shape)
104        end
105        if formatter then
106            commands.flow_set_text("node",formatter(current,comment))
107        else
108            commands.flow_set_text("node",nodecode)
109        end
110        if next then
111            commands.flow_set_connection("bt","",tostring(next))
112        end
113        if nodecode == "glyph" then
114            local components = current.components
115            if components then
116                commands.flow_set_connection("rl","",tostring(components))
117                commands.flow_stop_cell()
118                n = flow_nodes_to_chart { head = components, comment = "component",x = x+2, y = y-1 }
119            else
120                commands.flow_stop_cell()
121            end
122        elseif nodecode == "disc" then
123            local pre = current.pre
124            local pos = current.post
125            local rep = current.replace
126            if pre and not rep and not rep then
127                if pre then
128                    commands.flow_set_connection("rl","",tostring(pre))
129                end
130                commands.flow_stop_cell()
131                if pre then
132                    n = flow_nodes_to_chart { head = pre, comment = "prebreak", x = x+1, y = y-1 }
133                end
134            else
135                if pre then
136                    commands.flow_set_connection("rl","",tostring(pre))
137                end
138                if rep then
139                    commands.flow_set_connection("+rl","",tostring(rep))
140                end
141                if pos then
142                    commands.flow_set_connection("-rl","",tostring(pos))
143                end
144                commands.flow_stop_cell()
145                if pre then
146                    n = flow_nodes_to_chart{ head = pre, comment = "prebreak", x = x+1, y = y-1 }
147                end
148                if rep then
149                    n = flow_nodes_to_chart{ head = rep, comment = "replacement", x = x+3, y = y-1 }
150                end
151                if pos then
152                    n = flow_nodes_to_chart{ head = pos, comment = "postbreak", x = x+2, y = y-1 }
153                end
154            end
155        elseif nodecode == "hlist" then
156            local list = current.list
157            if list then
158                commands.flow_set_connection("rl","",tostring(list))
159                commands.flow_stop_cell()
160                n = flow_nodes_to_chart { head = list, comment = "list", x = x+2, y = y-1 }
161            else
162                commands.flow_stop_cell()
163            end
164        else
165            commands.flow_stop_cell()
166        end
167        current = next
168    end
169end
170
171function moduledata.charts.nodes.chart(specification)
172    commands.flow_start_chart(specification.name)
173    flow_nodes_to_chart(specification)
174    commands.flow_stop_chart()
175end
176