node-ppt.lua /size: 12 Kb    last modification: 2020-07-01 14:35
1
if
not
modules
then
modules
=
{
}
end
modules
[
'
node-ppt
'
]
=
{
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 is all very exeperimental and likely to change.
10 11
local
next
,
type
,
unpack
,
load
=
next
,
type
,
table
.
unpack
,
load
12 13
local
serialize
=
table
.
serialize
14
local
formatters
=
string
.
formatters
15 16
local
report
=
logs
.
reporter
(
"
properties
"
)
17
local
report_setting
=
logs
.
reporter
(
"
properties
"
,
"
setting
"
)
18
local
trace_setting
=
false
trackers
.
register
(
"
properties.setting
"
,
function
(
v
)
trace_setting
=
v
end
)
19 20
-- report("using experimental properties")
21 22
local
nuts
=
nodes
.
nuts
23
local
tonut
=
nuts
.
tonut
24
local
tonode
=
nuts
.
tonode
25
local
getid
=
nuts
.
getid
26
local
getnext
=
nuts
.
getnext
27
local
getprev
=
nuts
.
getprev
28
local
getsubtype
=
nuts
.
getsubtype
29
local
getlist
=
nuts
.
getlist
30
local
setlist
=
nuts
.
setlist
31
local
getprop
=
nuts
.
getprop
32 33
local
removenode
=
nuts
.
remove
34 35
local
nextnode
=
nuts
.
traversers
.
node
36
local
nextwhatsit
=
nuts
.
traversers
.
whatsit
37 38
local
nodecodes
=
nodes
.
nodecodes
39
local
whatsitcodes
=
nodes
.
whatsitcodes
40 41
local
whatsit_code
=
nodecodes
.
whatsit
42
local
hlist_code
=
nodecodes
.
hlist
43
local
vlist_code
=
nodecodes
.
vlist
44 45
local
userdefinedwhatsit_code
=
whatsitcodes
.
userdefined
46 47
local
nodepool
=
nodes
.
pool
48
local
new_usernode
=
nodepool
.
usernode
49 50
local
variables
=
interfaces
.
variables
51
local
v_before
=
variables
.
before
52
local
v_after
=
variables
.
after
53
local
v_here
=
variables
.
here
54 55
local
property_id
=
nodepool
.
userids
[
"
property
"
]
56 57
local
properties
=
nodes
.
properties
58
local
propertydata
=
properties
.
data
59 60
local
starttiming
=
statistics
.
starttiming
61
local
stoptiming
=
statistics
.
stoptiming
62 63
if
not
propertydata
then
64
return
65
end
66 67
-- management
68 69
local
function
register
(
where
,
data
,
...
)
70
if
not
data
then
71
data
=
where
72
where
=
v_after
73
end
74
if
data
then
75
nofslots
=
nofslots
+
1
76
return
new_usernode
(
property_id
,
{
where
,
data
,
...
}
)
77
end
78
end
79 80
local
writenode
=
node
.
write
81
local
flushnode
=
context
.
nodes
.
flush
82 83
function
commands
.
deferredproperty
(
...
)
84
-- context(register(...))
85
flushnode
(
register
(
...
)
)
86
end
87 88
function
commands
.
immediateproperty
(
...
)
89
writenode
(
register
(
...
)
)
90
end
91 92
commands
.
attachproperty
=
commands
.
deferredproperty
93 94
local
actions
=
{
}
properties
.
actions
=
actions
95 96
table
.
setmetatableindex
(
actions
,
function
(
t
,
k
)
97
report
(
"
unknown property action %a
"
,
k
)
98
return
function
(
)
end
99
end
)
100 101
local
f_delayed
=
formatters
[
"
return function(target,head,where,propdata,parent) %s end
"
]
102
local
f_immediate
=
formatters
[
"
return function(target,head,where,propdata) %s end
"
]
103 104
local
nofdelayed
=
0
-- better is to keep track of it per page ... we can have deleted nodes with properties
105
local
nofslots
=
0
106 107
function
actions
.
delayed
(
target
,
head
,
where
,
propdata
,
code
,
...
)
-- this one is used at the tex end
108
if
code
then
109
local
delayed
=
propdata
.
delayed
110
if
delayed
then
111
delayed
[
#
delayed
+
1
]
=
{
where
,
code
,
...
}
112
else
113
propdata
.
delayed
=
{
{
where
,
code
,
...
}
}
114
nofdelayed
=
nofdelayed
+
1
115
end
116
end
117
end
118 119
function
actions
.
fdelayed
(
target
,
head
,
where
,
propdata
,
code
,
...
)
-- this one is used at the tex end
120
if
code
then
121
local
delayed
=
propdata
.
delayed
122
if
delayed
then
123
delayed
[
#
delayed
+
1
]
=
{
false
,
code
,
...
}
124
else
125
propdata
.
delayed
=
{
{
false
,
code
,
...
}
}
126
nofdelayed
=
nofdelayed
+
1
127
end
128
end
129
end
130 131
function
actions
.
immediate
(
target
,
head
,
where
,
propdata
,
code
,
...
)
-- this one is used at the tex end
132
local
kind
=
type
(
code
)
133
if
kind
=
=
"
string
"
then
134
local
f
=
f_immediate
(
code
)
135
local
okay
,
err
=
load
(
f
)
136
if
okay
then
137
local
h
=
okay
(
)
(
target
,
head
,
where
,
propdata
,
...
)
138
if
h
and
h
~
=
head
then
139
return
h
140
end
141
end
142
elseif
kind
=
=
"
function
"
then
143
local
h
=
code
(
)
(
target
,
head
,
where
,
propdata
,
...
)
144
if
h
and
h
~
=
head
then
145
return
h
146
end
147
end
148
end
149 150
local
function
delayed
(
head
,
parent
)
-- direct based
151
for
target
,
id
in
nextnode
,
head
do
152
local
p
=
propertydata
[
target
]
153
if
p
then
154
local
delayed
=
p
.
delayed
155
if
delayed
then
156
for
i
=
1
,
#
delayed
do
157
local
d
=
delayed
[
i
]
158
local
code
=
d
[
2
]
159
local
kind
=
type
(
code
)
160
if
kind
=
=
"
string
"
then
161
code
,
err
=
load
(
f_delayed
(
code
)
)
162
if
code
then
163
code
=
code
(
)
164
end
165
end
166
local
where
=
d
[
1
]
167
if
where
then
168
local
h
=
code
(
target
,
where
,
head
,
p
,
parent
,
unpack
(
d
,
3
)
)
-- target where propdata head parent
169
if
h
and
h
~
=
head
then
170
head
=
h
171
end
172
else
173
code
(
unpack
(
d
,
3
)
)
174
end
175
end
176
p
.
delayed
=
nil
177
if
nofdelayed
=
=
1
then
178
nofdelayed
=
0
179
return
head
180
else
181
nofdelayed
=
nofdelayed
-
1
182
end
183
end
184
end
185
if
id
=
=
hlist_code
or
id
=
=
vlist_code
then
186
local
list
=
getlist
(
target
)
187
if
list
then
188
local
done
=
delayed
(
list
,
parent
)
189
if
done
then
190
setlist
(
target
,
done
)
191
end
192
if
nofdelayed
=
=
0
then
193
return
head
194
end
195
end
196
else
197
-- maybe also some more lists? but we will only use this for some
198
-- special cases .. who knows
199
end
200
end
201
return
head
202
end
203 204
function
properties
.
delayed
(
head
)
--
205
if
nofdelayed
>
0
then
206
-- if next(propertydata) then
207
starttiming
(
properties
)
208
head
=
delayed
(
head
)
209
stoptiming
(
properties
)
210
-- else
211
-- delayed = 0
212
-- end
213
end
214
return
head
215
end
216 217
-- more explicit ones too
218 219
local
anchored
=
{
220
[
v_before
]
=
function
(
n
)
221
while
n
do
222
n
=
getprev
(
n
)
223
if
getid
(
n
)
=
=
whatsit_code
and
getsubtype
(
n
)
=
=
user_code
and
getprop
(
n
,
"
id
"
)
=
=
property_id
then
224
-- continue
225
else
226
return
n
227
end
228
end
229
end
,
230
[
v_after
]
=
function
(
n
)
231
while
n
do
232
n
=
getnext
(
n
)
233
if
getid
(
n
)
=
=
whatsit_code
then
234
local
subtype
=
getsubtype
(
n
)
235
if
(
subtype
=
=
userdefinedwhatsit_code
and
getprop
(
n
,
"
id
"
)
=
=
property_id
)
then
236
-- continue
237
else
238
return
n
239
end
240
else
241
return
n
242
end
243
end
244
end
,
245
[
v_here
]
=
function
(
n
)
246
-- todo
247
end
,
248
}
249 250
table
.
setmetatableindex
(
anchored
,
function
(
t
,
k
)
251
local
v
=
anchored
[
v_after
]
252
t
[
k
]
=
v
253
return
v
254
end
)
255 256
function
properties
.
attach
(
head
)
257 258
if
nofslots
<
=
0
then
259
return
head
260
end
261 262
local
last
=
nil
263 264
starttiming
(
properties
)
265 266
for
source
,
subtype
in
nextwhatsit
,
head
do
267
if
subtype
=
=
userdefinedwhatsit_code
then
268
if
last
then
269
removenode
(
head
,
last
,
true
)
270
last
=
nil
271
end
272
if
getprop
(
source
,
"
id
"
)
=
=
property_id
then
273
local
data
=
getprop
(
source
,
"
data
"
)
274
if
data
then
275
local
where
=
data
[
1
]
276
local
target
=
anchored
[
where
]
(
source
)
277
if
target
then
278
local
first
=
data
[
2
]
279
local
method
=
type
(
first
)
280
local
p_target
=
propertydata
[
target
]
281
local
p_source
=
propertydata
[
source
]
282
if
p_target
then
283
if
p_source
then
284
for
k
,
v
in
next
,
p_source
do
285
p_target
[
k
]
=
v
286
end
287
end
288
if
method
=
=
"
table
"
then
289
for
k
,
v
in
next
,
first
do
290
p_target
[
k
]
=
v
291
end
292
elseif
method
=
=
"
function
"
then
293
first
(
target
,
head
,
where
,
p_target
,
unpack
(
data
,
3
)
)
294
elseif
method
=
=
"
string
"
then
295
actions
[
first
]
(
target
,
head
,
where
,
p_target
,
unpack
(
data
,
3
)
)
296
end
297
elseif
p_source
then
298
if
method
=
=
"
table
"
then
299
propertydata
[
target
]
=
p_source
300
for
k
,
v
in
next
,
first
do
301
p_source
[
k
]
=
v
302
end
303
elseif
method
=
=
"
function
"
then
304
propertydata
[
target
]
=
p_source
305
first
(
target
,
head
,
where
,
p_source
,
unpack
(
data
,
3
)
)
306
elseif
method
=
=
"
string
"
then
307
propertydata
[
target
]
=
p_source
308
actions
[
first
]
(
target
,
head
,
where
,
p_source
,
unpack
(
data
,
3
)
)
309
end
310
else
311
if
method
=
=
"
table
"
then
312
propertydata
[
target
]
=
first
313
elseif
method
=
=
"
function
"
then
314
local
t
=
{
}
315
propertydata
[
target
]
=
t
316
first
(
target
,
head
,
where
,
t
,
unpack
(
data
,
3
)
)
317
elseif
method
=
=
"
string
"
then
318
local
t
=
{
}
319
propertydata
[
target
]
=
t
320
actions
[
first
]
(
target
,
head
,
where
,
t
,
unpack
(
data
,
3
)
)
321
end
322
end
323
if
trace_setting
then
324
report_setting
(
"
node %i, id %s, data %s
"
,
325
target
,
nodecodes
[
getid
(
target
)
]
,
serialize
(
propertydata
[
target
]
,
false
)
)
326
end
327
end
328
if
nofslots
=
=
1
then
329
nofslots
=
0
330
last
=
source
331
break
332
else
333
nofslots
=
nofslots
-
1
334
end
335
end
336
last
=
source
337
end
338
end
339
end
340 341
if
last
then
342
removenode
(
head
,
last
,
true
)
343
end
344 345
stoptiming
(
properties
)
346 347
return
head
348 349
end
350 351
-- maybe better hard coded in-place
352 353
statistics
.
register
(
"
properties processing time
"
,
function
(
)
354
return
statistics
.
elapsedseconds
(
properties
)
355
end
)
356 357
-- only for development
358 359
-- local tasks = nodes.tasks
360
--
361
-- local function show(head,level,report)
362
-- for target in nextnode, head do
363
-- local p = propertydata[target]
364
-- if p then
365
-- report("level %i, node %i, id %s, data %s",
366
-- level,target,nodecodes[getid(target)],serialize(propertydata[target],false))
367
-- end
368
-- local id = getid(target)
369
-- if id == hlist_code or id == vlist_code then
370
-- local list = getlist(target)
371
-- if list then
372
-- show(list,level+1,report)
373
-- end
374
-- else
375
-- -- maybe more lists
376
-- end
377
-- end
378
-- return head, false
379
-- end
380
--
381
-- local report_shipout = logs.reporter("properties","shipout")
382
-- local report_processors = logs.reporter("properties","processors")
383
--
384
-- function properties.showshipout (head) return tonode(show(tonut(head),1,report_shipout )), true end
385
-- function properties.showprocessors(head) return tonode(show(tonut(head),1,report_processors)), true end
386
--
387
-- tasks.prependaction("shipouts","before","nodes.properties.showshipout")
388
-- tasks.disableaction("shipouts","nodes.properties.showshipout")
389
--
390
-- trackers.register("properties.shipout",function(v)
391
-- tasks.setaction("shipouts","nodes.properties.showshipout",v)
392
-- end)
393
--
394
-- tasks.appendaction ("processors","after","nodes.properties.showprocessors")
395
-- tasks.disableaction("processors","nodes.properties.showprocessors")
396
--
397
-- trackers.register("properties.processors",function(v)
398
-- tasks.setaction("processors","nodes.properties.showprocessors",v)
399
-- end)
400