page-lin.lua /size: 14 Kb    last modification: 2020-07-01 14:35
1
if
not
modules
then
modules
=
{
}
end
modules
[
'
page-lin
'
]
=
{
2
version
=
1
.
001
,
3
comment
=
"
companion to page-lin.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
-- experimental -> will become builders
10 11
-- if there is demand for it, we can support multiple numbering streams
12
-- and use more than one attibute
13 14
local
next
,
tonumber
=
next
,
tonumber
15 16
local
trace_numbers
=
false
trackers
.
register
(
"
lines.numbers
"
,
function
(
v
)
trace_numbers
=
v
end
)
17 18
local
report_lines
=
logs
.
reporter
(
"
lines
"
)
19 20
local
attributes
=
attributes
21
local
nodes
=
nodes
22
local
context
=
context
23 24
local
implement
=
interfaces
.
implement
25 26
nodes
.
lines
=
nodes
.
lines
or
{
}
27
local
lines
=
nodes
.
lines
28 29
lines
.
data
=
lines
.
data
or
{
}
-- start step tag
30
local
data
=
lines
.
data
31
local
last
=
#
data
32 33
lines
.
scratchbox
=
lines
.
scratchbox
or
0
34 35
storage
.
register
(
"
lines/data
"
,
data
,
"
nodes.lines.data
"
)
36 37
local
variables
=
interfaces
.
variables
38 39
local
v_next
=
variables
.
next
40
local
v_page
=
variables
.
page
41
local
v_no
=
variables
.
no
42 43
local
properties
=
nodes
.
properties
.
data
44 45
local
nodecodes
=
nodes
.
nodecodes
46
local
listcodes
=
nodes
.
listcodes
47 48
local
hlist_code
=
nodecodes
.
hlist
49
local
vlist_code
=
nodecodes
.
vlist
50
local
whatsit_code
=
nodecodes
.
whatsit
51
local
glyph_code
=
nodecodes
.
glyph
52 53
local
linelist_code
=
listcodes
.
line
54 55
local
a_displaymath
=
attributes
.
private
(
'
displaymath
'
)
56
local
a_linenumber
=
attributes
.
private
(
'
linenumber
'
)
57
local
a_linereference
=
attributes
.
private
(
'
linereference
'
)
58
----- a_verbatimline = attributes.private('verbatimline')
59 60
local
current_list
=
{
}
61
local
cross_references
=
{
}
62
local
chunksize
=
250
-- not used in boxed
63 64
local
nuts
=
nodes
.
nuts
65 66
local
getid
=
nuts
.
getid
67
local
getsubtype
=
nuts
.
getsubtype
68
local
getnext
=
nuts
.
getnext
69
local
getattr
=
nuts
.
getattr
70
local
setattr
=
nuts
.
setattr
71
local
getlist
=
nuts
.
getlist
72
local
getbox
=
nuts
.
getbox
73
----- getdirection = nuts.getdirection
74
----- getwidth = nuts.getwidth
75
local
getheight
=
nuts
.
getheight
76
local
getdepth
=
nuts
.
getdepth
77 78
local
setprop
=
nuts
.
setprop
79
local
getprop
=
nuts
.
getprop
80 81
local
nexthlist
=
nuts
.
traversers
.
hlist
82
local
nextvlist
=
nuts
.
traversers
.
vlist
83 84
local
copy_node
=
nuts
.
copy
85
----- hpack_nodes = nuts.hpack
86
local
is_display_math
=
nuts
.
is_display_math
87
local
leftmarginwidth
=
nuts
.
leftmarginwidth
88 89
----- nodepool = nuts.pool
90
----- new_kern = nodepool.kern
91 92
local
ctx_convertnumber
=
context
.
convertnumber
93
local
ctx_makelinenumber
=
context
.
makelinenumber
94 95
local
paragraphs
=
typesetters
.
paragraphs
96
local
addtoline
=
paragraphs
.
addtoline
97
local
checkline
=
paragraphs
.
checkline
98
local
moveinline
=
paragraphs
.
moveinline
99 100
-- cross referencing
101 102
function
lines
.
number
(
n
)
103
n
=
tonumber
(
n
)
104
local
cr
=
cross_references
[
n
]
or
0
105
cross_references
[
n
]
=
nil
106
return
cr
107
end
108 109
local
function
resolve
(
n
,
m
)
-- we can now check the 'line' flag (todo)
110
while
n
do
111
local
id
=
getid
(
n
)
112
if
id
=
=
whatsit_code
then
-- why whatsit
113
local
a
=
getattr
(
n
,
a_linereference
)
114
if
a
then
115
cross_references
[
a
]
=
m
116
end
117
elseif
id
=
=
hlist_code
or
id
=
=
vlist_code
then
118
resolve
(
getlist
(
n
)
,
m
)
119
end
120
n
=
getnext
(
n
)
121
end
122
end
123 124
function
lines
.
finalize
(
t
)
125
local
getnumber
=
lines
.
number
126
for
_
,
p
in
next
,
t
do
127
for
_
,
r
in
next
,
p
do
128
local
m
=
r
.
metadata
129
if
m
and
m
.
kind
=
=
"
line
"
then
130
local
e
=
r
.
entries
131
local
u
=
r
.
userdata
132
e
.
linenumber
=
getnumber
(
e
.
text
or
0
)
-- we can nil e.text
133
e
.
conversion
=
u
and
u
.
conversion
134
r
.
userdata
=
nil
-- hack
135
end
136
end
137
end
138
end
139 140
local
filters
=
structures
.
references
.
filters
141
local
helpers
=
structures
.
helpers
142 143
structures
.
references
.
registerfinalizer
(
lines
.
finalize
)
144 145
filters
.
line
=
filters
.
line
or
{
}
146 147
function
filters
.
line
.
default
(
data
)
148
-- helpers.title(data.entries.linenumber or "?",data.metadata)
149
ctx_convertnumber
(
data
.
entries
.
conversion
or
"
numbers
"
,
data
.
entries
.
linenumber
or
"
0
"
)
150
end
151 152
function
filters
.
line
.
page
(
data
,
prefixspec
,
pagespec
)
-- redundant
153
helpers
.
prefixpage
(
data
,
prefixspec
,
pagespec
)
154
end
155 156
function
filters
.
line
.
linenumber
(
data
)
-- raw
157
context
(
data
.
entries
.
linenumber
or
"
0
"
)
158
end
159 160
-- boxed variant, todo: use number mechanism
161 162
lines
.
boxed
=
{
}
163
local
boxed
=
lines
.
boxed
164 165
-- todo: cache setups, and free id no longer used
166
-- use interfaces.cachesetup(t)
167 168
function
boxed
.
register
(
configuration
)
169
last
=
last
+
1
170
data
[
last
]
=
configuration
171
if
trace_numbers
then
172
report_lines
(
"
registering setup %a
"
,
last
)
173
end
174
return
last
175
end
176 177
implement
{
178
name
=
"
registerlinenumbering
"
,
179
actions
=
{
boxed
.
register
,
context
}
,
180
arguments
=
{
181
{
182
{
"
continue
"
}
,
183
{
"
start
"
,
"
integer
"
}
,
184
{
"
step
"
,
"
integer
"
}
,
185
{
"
method
"
}
,
186
{
"
tag
"
}
,
187
}
188
}
189
}
190 191
function
boxed
.
setup
(
n
,
configuration
)
192
local
d
=
data
[
n
]
193
if
d
then
194
if
trace_numbers
then
195
report_lines
(
"
updating setup %a
"
,
n
)
196
end
197
for
k
,
v
in
next
,
configuration
do
198
d
[
k
]
=
v
199
end
200
else
201
if
trace_numbers
then
202
report_lines
(
"
registering setup %a (br)
"
,
n
)
203
end
204
data
[
n
]
=
configuration
205
end
206
return
n
207
end
208 209
implement
{
210
name
=
"
setuplinenumbering
"
,
211
actions
=
boxed
.
setup
,
212
arguments
=
{
213
"
integer
"
,
214
{
215
{
"
continue
"
}
,
216
{
"
start
"
,
"
integer
"
}
,
217
{
"
step
"
,
"
integer
"
}
,
218
{
"
method
"
}
,
219
{
"
tag
"
}
,
220
}
221
}
222
}
223 224
local
function
check_number
(
n
,
a
,
skip
,
sameline
)
225
local
d
=
data
[
a
]
226
if
d
then
227
local
tag
=
d
.
tag
or
"
"
228
local
skipflag
=
0
229
local
s
=
d
.
start
or
1
230
current_list
[
#
current_list
+
1
]
=
{
n
,
s
}
231
if
sameline
then
232
skipflag
=
0
233
if
trace_numbers
then
234
report_lines
(
"
skipping broken line number %s for setup %a: %s (%s)
"
,
#
current_list
,
a
,
s
,
d
.
continue
or
v_no
)
235
end
236
elseif
not
skip
and
s
%
d
.
step
=
=
0
then
237
skipflag
,
d
.
start
=
1
,
s
+
1
-- (d.step or 1)
238
if
trace_numbers
then
239
report_lines
(
"
making number %s for setup %a: %s (%s)
"
,
#
current_list
,
a
,
s
,
d
.
continue
or
v_no
)
240
end
241
else
242
skipflag
,
d
.
start
=
0
,
s
+
1
-- (d.step or 1)
243
if
trace_numbers
then
244
report_lines
(
"
skipping line number %s for setup %a: %s (%s)
"
,
#
current_list
,
a
,
s
,
d
.
continue
or
v_no
)
245
end
246
end
247
local
p
=
checkline
(
n
)
248
if
p
then
249
ctx_makelinenumber
(
tag
,
skipflag
,
s
,
p
.
hsize
,
p
.
reverse
and
1
or
0
)
250
else
251
report_lines
(
"
needs checking
"
)
252
end
253
end
254
end
255 256
-- print(nodes.idstostring(list))
257 258
-- hlists of type line will only have an attribute when the line number attribute
259
-- still set at par building time which is not always the case unless we explicitly
260
-- do a par before we end the line
261 262
-- todo: check for a: when <= 0 then false
263 264
local
function
lineisnumbered
(
n
)
265
local
n
=
getlist
(
n
)
266
while
n
do
267
local
id
=
getid
(
n
)
268
if
id
=
=
hlist_code
or
id
=
=
vlist_code
then
269
-- this can hit fast as we inherit anchor attributes from parent
270
local
a
=
getattr
(
n
,
a_linenumber
)
271
if
a
and
a
>
0
then
272
return
a
273
end
274
elseif
id
=
=
glyph_code
then
275
local
a
=
getattr
(
n
,
a_linenumber
)
276
if
a
and
a
>
0
then
277
return
a
278
else
279
return
false
280
end
281
end
282
n
=
getnext
(
n
)
283
end
284
end
285 286
local
function
listisnumbered
(
list
)
287
if
list
then
288
for
n
,
subtype
in
nexthlist
,
list
do
289
if
subtype
=
=
linelist_code
then
290
local
a
=
getattr
(
n
,
a_linenumber
)
291
if
a
then
292
-- a quick test for lines (only valid when \par before \stoplinenumbering)
293
return
a
>
0
and
list
or
false
294
else
295
-- a bit slower one, assuming that we have normalized and anchored
296
if
lineisnumbered
(
n
)
then
297
return
list
298
end
299
end
300
end
301
end
302
end
303
end
304 305
local
function
findnumberedlist
(
list
)
306
-- we assume wrapped boxes, only one with numbers
307
local
n
=
list
308
while
n
do
309
local
id
=
getid
(
n
)
310
if
id
=
=
hlist_code
then
311
if
getsubtype
(
n
)
=
=
linelist_code
then
312
local
a
=
getattr
(
n
,
a_linenumber
)
313
if
a
then
314
return
a
>
0
and
list
315
end
316
return
317
else
318
local
list
=
getlist
(
n
)
319
if
lineisnumbered
(
list
)
then
320
return
n
321
end
322
local
okay
=
findnumberedlist
(
list
)
323
if
okay
then
324
return
okay
325
end
326
end
327
elseif
id
=
=
vlist_code
then
328
local
list
=
getlist
(
n
)
329
if
listisnumbered
(
list
)
then
330
return
list
331
end
332
local
okay
=
findnumberedlist
(
list
)
333
if
okay
then
334
return
okay
335
end
336
elseif
id
=
=
glyph_code
then
337
return
338
end
339
n
=
getnext
(
n
)
340
end
341
end
342 343
-- reset ranges per page
344
-- store first and last per page
345
-- maybe just set marks directly
346 347
local
function
findcolumngap
(
list
)
348
-- we assume wrapped boxes, only one with numbers
349
local
n
=
list
350
while
n
do
351
local
id
=
getid
(
n
)
352
if
id
=
=
hlist_code
or
id
=
=
vlist_code
then
353
local
p
=
properties
[
n
]
354
if
p
and
p
.
columngap
then
355
if
trace_numbers
then
356
report_lines
(
"
first column gap %a
"
,
p
.
columngap
)
357
end
358
return
n
359
else
360
local
list
=
getlist
(
n
)
361
if
list
then
362
local
okay
=
findcolumngap
(
list
)
363
if
okay
then
364
return
okay
365
end
366
end
367
end
368
end
369
n
=
getnext
(
n
)
370
end
371
end
372 373
function
boxed
.
stage_one
(
n
,
nested
)
374
current_list
=
{
}
375
local
box
=
getbox
(
n
)
376
if
not
box
then
377
return
378
end
379
local
list
=
getlist
(
box
)
380
if
not
list
then
381
return
382
end
383
local
last_a
=
nil
384
local
last_v
=
-1
385
local
skip
=
false
386 387
local
function
check
(
)
388
for
n
,
subtype
in
nexthlist
,
list
do
389
if
subtype
~
=
linelist_code
then
390
-- go on
391
elseif
getheight
(
n
)
=
=
0
and
getdepth
(
n
)
=
=
0
then
392
-- skip funny hlists -- todo: check line subtype
393
else
394
local
a
=
lineisnumbered
(
n
)
395
if
a
then
396
if
last_a
~
=
a
then
397
local
da
=
data
[
a
]
398
local
ma
=
da
.
method
399
if
ma
=
=
v_next
then
400
skip
=
true
401
elseif
ma
=
=
v_page
then
402
da
.
start
=
1
-- eventually we will have a normal counter
403
end
404
last_a
=
a
405
if
trace_numbers
then
406
report_lines
(
"
starting line number range %s: start %s, continue %s
"
,
a
,
da
.
start
,
da
.
continue
or
v_no
)
407
end
408
end
409
if
getattr
(
n
,
a_displaymath
)
then
410
-- this probably needs to be adapted !
411
if
is_display_math
(
n
)
then
412
check_number
(
n
,
a
,
skip
)
413
end
414
else
415
-- -- we now prevent nesting anyway .. maybe later we need to check again
416
-- local v = getattr(list,a_verbatimline)
417
-- if not v or v ~= last_v then
418
-- last_v = v
419
check_number
(
n
,
a
,
skip
)
420
-- else
421
-- check_number(n,a,skip,true)
422
-- end
423
end
424
skip
=
false
425
end
426
end
427
end
428
end
429 430
if
nested
=
=
0
then
431
if
list
then
432
check
(
)
433
end
434
elseif
nested
=
=
1
then
435
local
id
=
getid
(
box
)
436
if
id
=
=
vlist_code
then
437
if
listisnumbered
(
list
)
then
438
-- ok
439
else
440
list
=
findnumberedlist
(
list
)
441
end
442
else
-- hlist
443
list
=
findnumberedlist
(
list
)
444
end
445
if
list
then
446
check
(
)
447
end
448
elseif
nested
=
=
2
then
449
list
=
findcolumngap
(
list
)
450
-- we assume we have a vlist
451
if
not
list
then
452
return
453
end
454
for
n
in
nextvlist
,
list
do
455
local
p
=
properties
[
n
]
456
if
p
and
p
.
columngap
then
457
if
trace_numbers
then
458
report_lines
(
"
found column gap %a
"
,
p
.
columngap
)
459
end
460
list
=
getlist
(
n
)
461
if
list
then
462
check
(
)
463
end
464
end
465
end
466
else
467
-- bad call
468
end
469
end
470 471
-- column attribute
472 473
function
boxed
.
stage_two
(
n
,
m
)
474
if
#
current_list
>
0
then
475
m
=
m
or
lines
.
scratchbox
476
local
t
=
{
}
477
local
tn
=
0
478
for
l
in
nexthlist
,
getlist
(
getbox
(
m
)
)
do
479
tn
=
tn
+
1
480
t
[
tn
]
=
copy_node
(
l
)
-- use take_box instead
481
end
482
for
i
=
1
,
#
current_list
do
483
local
li
=
current_list
[
i
]
484
local
n
=
li
[
1
]
485
local
m
=
li
[
2
]
486
local
ti
=
t
[
i
]
487
if
ti
then
488
addtoline
(
n
,
ti
)
489
resolve
(
n
,
m
)
490
else
491
report_lines
(
"
error in linenumbering (1)
"
)
492
return
493
end
494
end
495
end
496
end
497 498
-- function boxed.stage_zero(n) -- not used
499
-- return identify(getlist(getbox(n)))
500
-- end
501 502
implement
{
503
name
=
"
linenumbersstageone
"
,
504
actions
=
boxed
.
stage_one
,
505
arguments
=
{
"
integer
"
,
"
integer
"
}
506
}
507 508
implement
{
509
name
=
"
linenumbersstagetwo
"
,
510
actions
=
boxed
.
stage_two
,
511
arguments
=
{
"
integer
"
,
"
integer
"
}
512
}
513