supp-box.lua /size: 24 Kb    last modification: 2020-07-01 14:35
1
if
not
modules
then
modules
=
{
}
end
modules
[
'
supp-box
'
]
=
{
2
version
=
1
.
001
,
3
comment
=
"
companion to supp-box.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 preliminary code, use insert_before etc
10 11
local
report_hyphenation
=
logs
.
reporter
(
"
languages
"
,
"
hyphenation
"
)
12 13
local
tonumber
,
next
,
type
=
tonumber
,
next
,
type
14 15
local
lpegmatch
=
lpeg
.
match
16 17
local
tex
=
tex
18
local
context
=
context
19
local
nodes
=
nodes
20 21
local
implement
=
interfaces
.
implement
22 23
local
nodecodes
=
nodes
.
nodecodes
24 25
local
disc_code
=
nodecodes
.
disc
26
local
hlist_code
=
nodecodes
.
hlist
27
local
vlist_code
=
nodecodes
.
vlist
28
local
glue_code
=
nodecodes
.
glue
29
local
penalty_code
=
nodecodes
.
penalty
30
local
glyph_code
=
nodecodes
.
glyph
31
local
localpar_code
=
nodecodes
.
localpar
32 33
local
indent_code
=
nodes
.
listcodes
.
indent
34 35
local
hmode_code
=
tex
.
modelevels
.
horizontal
36 37
local
nuts
=
nodes
.
nuts
38
local
tonut
=
nuts
.
tonut
39
local
tonode
=
nuts
.
tonode
40 41
----- getfield = nuts.getfield
42
local
getnext
=
nuts
.
getnext
43
local
getprev
=
nuts
.
getprev
44
local
getboth
=
nuts
.
getboth
45
local
getdisc
=
nuts
.
getdisc
46
local
getid
=
nuts
.
getid
47
local
getsubtype
=
nuts
.
getsubtype
48
local
getlist
=
nuts
.
getlist
49
local
getattribute
=
nuts
.
getattribute
50
local
getbox
=
nuts
.
getbox
51
local
getdirection
=
nuts
.
getdirection
52
local
getwidth
=
nuts
.
getwidth
53
local
takebox
=
nuts
.
takebox
54 55
----- setfield = nuts.setfield
56
local
setlink
=
nuts
.
setlink
57
local
setboth
=
nuts
.
setboth
58
local
setnext
=
nuts
.
setnext
59
local
setprev
=
nuts
.
setprev
60
local
setbox
=
nuts
.
setbox
61
local
setlist
=
nuts
.
setlist
62
local
setdisc
=
nuts
.
setdisc
63
local
setwidth
=
nuts
.
setwidth
64
local
setheight
=
nuts
.
setheight
65
local
setdepth
=
nuts
.
setdepth
66
local
setshift
=
nuts
.
setshift
67
local
setsplit
=
nuts
.
setsplit
68
local
setattrlist
=
nuts
.
setattrlist
69 70
local
flush_node
=
nuts
.
flush_node
71
local
flush_list
=
nuts
.
flush_list
72
local
copy_node
=
nuts
.
copy
73
local
copy_list
=
nuts
.
copy_list
74
local
find_tail
=
nuts
.
tail
75
local
getdimensions
=
nuts
.
dimensions
76
local
hpack
=
nuts
.
hpack
77
local
vpack
=
nuts
.
vpack
78
local
traverse_id
=
nuts
.
traverse_id
79
local
traverse
=
nuts
.
traverse
80
local
free
=
nuts
.
free
81
local
findtail
=
nuts
.
tail
82 83
local
nextdisc
=
nuts
.
traversers
.
disc
84
local
nextdir
=
nuts
.
traversers
.
dir
85
local
nexthlist
=
nuts
.
traversers
.
hlist
86 87
local
listtoutf
=
nodes
.
listtoutf
88 89
local
nodepool
=
nuts
.
pool
90
local
new_penalty
=
nodepool
.
penalty
91
local
new_hlist
=
nodepool
.
hlist
92
local
new_glue
=
nodepool
.
glue
93 94
local
setlistcolor
=
nodes
.
tracers
.
colors
.
setlist
95 96
local
texget
=
tex
.
get
97
local
texgetbox
=
tex
.
getbox
98
local
texsetdimen
=
tex
.
setdimen
99
local
texgetnest
=
tex
.
getnest
100 101
local
function
hyphenatedlist
(
head
,
usecolor
)
102
local
current
=
head
and
tonut
(
head
)
103
while
current
do
104
local
id
=
getid
(
current
)
105
local
prev
,
next
=
getboth
(
current
)
106
if
id
=
=
disc_code
then
107
local
pre
,
post
,
replace
=
getdisc
(
current
)
108
if
not
usecolor
then
109
-- nothing fancy done
110
elseif
pre
and
post
then
111
setlistcolor
(
pre
,
"
darkmagenta
"
)
112
setlistcolor
(
post
,
"
darkcyan
"
)
113
elseif
pre
then
114
setlistcolor
(
pre
,
"
darkyellow
"
)
115
elseif
post
then
116
setlistcolor
(
post
,
"
darkyellow
"
)
117
end
118
if
replace
then
119
flush_list
(
replace
)
120
end
121
setdisc
(
current
)
122
if
pre
then
123
setlink
(
prev
,
new_penalty
(
10000
)
,
pre
)
124
setlink
(
find_tail
(
pre
)
,
current
)
125
end
126
if
post
then
127
setlink
(
current
,
new_penalty
(
10000
)
,
post
)
128
setlink
(
find_tail
(
post
)
,
next
)
129
end
130
elseif
id
=
=
vlist_code
or
id
=
=
hlist_code
then
131
hyphenatedlist
(
getlist
(
current
)
)
132
end
133
current
=
next
134
end
135
end
136 137
implement
{
138
name
=
"
hyphenatedlist
"
,
139
arguments
=
{
"
integer
"
,
"
boolean
"
}
,
140
actions
=
function
(
n
,
color
)
141
local
b
=
texgetbox
(
n
)
142
if
b
then
143
hyphenatedlist
(
b
.
list
,
color
)
144
end
145
end
146
}
147 148
-- local function hyphenatedhack(head,pre)
149
-- pre = tonut(pre)
150
-- for n in nextdisc, tonut(head) do
151
-- local hyphen = getfield(n,"pre")
152
-- if hyphen then
153
-- flush_list(hyphen)
154
-- end
155
-- setfield(n,"pre",copy_list(pre))
156
-- end
157
-- end
158
--
159
-- commands.hyphenatedhack = hyphenatedhack
160 161
local
function
checkedlist
(
list
)
162
if
type
(
list
)
=
=
"
number
"
then
163
return
getlist
(
getbox
(
tonut
(
list
)
)
)
164
else
165
return
tonut
(
list
)
166
end
167
end
168 169
implement
{
170
name
=
"
showhyphenatedinlist
"
,
171
arguments
=
"
integer
"
,
172
actions
=
function
(
n
)
173
-- we just hyphenate (as we pass a hpack) .. a bit too much casting but ...
174
local
l
=
languages
.
hyphenators
.
handler
(
tonode
(
checkedlist
(
n
)
)
)
175
report_hyphenation
(
"
show: %s
"
,
listtoutf
(
l
,
false
,
true
)
)
176
end
177
}
178 179
local
function
applytochars
(
current
,
doaction
,
noaction
,
nested
)
180
while
current
do
181
local
id
=
getid
(
current
)
182
if
nested
and
(
id
=
=
hlist_code
or
id
=
=
vlist_code
)
then
183
context
.
beginhbox
(
)
184
applytochars
(
getlist
(
current
)
,
doaction
,
noaction
,
nested
)
185
context
.
endhbox
(
)
186
elseif
id
~
=
glyph_code
then
187
noaction
(
tonode
(
copy_node
(
current
)
)
)
188
else
189
doaction
(
tonode
(
copy_node
(
current
)
)
)
190
end
191
current
=
getnext
(
current
)
192
end
193
end
194 195
local
function
applytowords
(
current
,
doaction
,
noaction
,
nested
)
196
local
start
197
while
current
do
198
local
id
=
getid
(
current
)
199
if
id
=
=
glue_code
then
200
if
start
then
201
doaction
(
tonode
(
copy_list
(
start
,
current
)
)
)
202
start
=
nil
203
end
204
noaction
(
tonode
(
copy_node
(
current
)
)
)
205
elseif
nested
and
(
id
=
=
hlist_code
or
id
=
=
vlist_code
)
then
206
context
.
beginhbox
(
)
207
applytowords
(
getlist
(
current
)
,
doaction
,
noaction
,
nested
)
208
context
.
egroup
(
)
209
elseif
not
start
then
210
start
=
current
211
end
212
current
=
getnext
(
current
)
213
end
214
if
start
then
215
doaction
(
tonode
(
copy_list
(
start
)
)
)
216
end
217
end
218 219
local
methods
=
{
220
char
=
applytochars
,
221
characters
=
applytochars
,
222
word
=
applytowords
,
223
words
=
applytowords
,
224
}
225 226
implement
{
227
name
=
"
applytobox
"
,
228
arguments
=
{
229
{
230
{
"
box
"
,
"
integer
"
}
,
231
{
"
command
"
}
,
232
{
"
method
"
}
,
233
{
"
nested
"
,
"
boolean
"
}
,
234
}
235
}
,
236
actions
=
function
(
specification
)
237
local
list
=
checkedlist
(
specification
.
box
)
238
local
action
=
methods
[
specification
.
method
or
"
char
"
]
239
if
list
and
action
then
240
action
(
list
,
context
[
specification
.
command
or
"
ruledhbox
"
]
,
context
,
specification
.
nested
)
241
end
242
end
243
}
244 245
local
split_char
=
lpeg
.
Ct
(
lpeg
.
C
(
1
)
^
0
)
246
local
split_word
=
lpeg
.
tsplitat
(
lpeg
.
patterns
.
space
)
247
local
split_line
=
lpeg
.
tsplitat
(
lpeg
.
patterns
.
eol
)
248 249
local
function
processsplit
(
specification
)
250
local
str
=
specification
.
data
or
"
"
251
local
command
=
specification
.
command
or
"
ruledhbox
"
252
local
method
=
specification
.
method
or
"
word
"
253
local
spaced
=
specification
.
spaced
254
if
method
=
=
"
char
"
or
method
=
=
"
character
"
then
255
local
words
=
lpegmatch
(
split_char
,
str
)
256
for
i
=
1
,
#
words
do
257
local
word
=
words
[
i
]
258
if
word
=
=
"
"
then
259
if
spaced
then
260
context
.
space
(
)
261
end
262
elseif
command
then
263
context
[
command
]
(
word
)
264
else
265
context
(
word
)
266
end
267
end
268
elseif
method
=
=
"
word
"
then
269
local
words
=
lpegmatch
(
split_word
,
str
)
270
for
i
=
1
,
#
words
do
271
local
word
=
words
[
i
]
272
if
spaced
and
i
>
1
then
273
context
.
space
(
)
274
end
275
if
command
then
276
context
[
command
]
(
word
)
277
else
278
context
(
word
)
279
end
280
end
281
elseif
method
=
=
"
line
"
then
282
local
words
=
lpegmatch
(
split_line
,
str
)
283
for
i
=
1
,
#
words
do
284
local
word
=
words
[
i
]
285
if
spaced
and
i
>
1
then
286
context
.
par
(
)
287
end
288
if
command
then
289
context
[
command
]
(
word
)
290
else
291
context
(
word
)
292
end
293
end
294
else
295
context
(
str
)
296
end
297
end
298 299
implement
{
300
name
=
"
processsplit
"
,
301
actions
=
processsplit
,
302
arguments
=
{
303
{
304
{
"
data
"
}
,
305
{
"
command
"
}
,
306
{
"
method
"
}
,
307
{
"
spaced
"
,
"
boolean
"
}
,
308
}
309
}
310
}
311 312
local
a_vboxtohboxseparator
=
attributes
.
private
(
"
vboxtohboxseparator
"
)
313 314
implement
{
315
name
=
"
vboxlisttohbox
"
,
316
arguments
=
{
"
integer
"
,
"
integer
"
,
"
dimen
"
}
,
317
actions
=
function
(
original
,
target
,
inbetween
)
318
local
current
=
getlist
(
getbox
(
original
)
)
319
local
head
=
nil
320
local
tail
=
nil
321
while
current
do
322
local
id
=
getid
(
current
)
323
local
next
=
getnext
(
current
)
324
if
id
=
=
hlist_code
then
325
local
list
=
getlist
(
current
)
326
if
head
then
327
if
inbetween
>
0
then
328
local
n
=
new_glue
(
0
,
0
,
inbetween
)
329
setlink
(
tail
,
n
)
330
tail
=
n
331
end
332
setlink
(
tail
,
list
)
333
else
334
head
=
list
335
end
336
tail
=
find_tail
(
list
)
337
-- remove last separator
338
if
getid
(
tail
)
=
=
hlist_code
and
getattribute
(
tail
,
a_vboxtohboxseparator
)
=
=
1
then
339
local
temp
=
tail
340
local
prev
=
getprev
(
tail
)
341
if
next
then
342
local
list
=
getlist
(
tail
)
343
setlink
(
prev
,
list
)
344
setlist
(
tail
)
345
tail
=
find_tail
(
list
)
346
else
347
tail
=
prev
348
end
349
flush_node
(
temp
)
350
end
351
-- done
352
setnext
(
tail
)
353
setlist
(
current
)
354
end
355
current
=
next
356
end
357
local
result
=
new_hlist
(
)
358
setlist
(
result
,
head
)
359
setbox
(
target
,
result
)
360
-- setbox(target,new_hlist(head))
361
end
362
}
363 364
implement
{
365
name
=
"
hboxtovbox
"
,
366
arguments
=
"
integer
"
,
367
actions
=
function
(
n
)
368
local
b
=
getbox
(
n
)
369
local
factor
=
texget
(
"
baselineskip
"
,
false
)
/
texget
(
"
hsize
"
)
370
setdepth
(
b
,
0
)
371
setheight
(
b
,
getwidth
(
b
)
*
factor
)
372
end
373
}
374 375
implement
{
376
name
=
"
boxtostring
"
,
377
arguments
=
"
integer
"
,
378
actions
=
function
(
n
)
379
context
.
puretext
(
nodes
.
toutf
(
texgetbox
(
n
)
.
list
)
)
-- helper is defined later
380
end
381
}
382 383
local
function
getnaturaldimensions
(
n
)
384
local
w
=
0
385
local
h
=
0
386
local
d
=
0
387
local
l
=
getlist
(
getbox
(
n
)
)
388
if
l
then
389
w
,
h
,
d
=
getdimensions
(
l
)
390
end
391
texsetdimen
(
"
lastnaturalboxwd
"
,
w
)
392
texsetdimen
(
"
lastnaturalboxht
"
,
h
)
393
texsetdimen
(
"
lastnaturalboxdp
"
,
d
)
394
return
w
,
h
,
d
395
end
396 397
implement
{
398
name
=
"
getnaturaldimensions
"
,
399
arguments
=
"
integer
"
,
400
actions
=
getnaturaldimensions
401
}
402 403
implement
{
404
name
=
"
naturalwd
"
,
405
arguments
=
"
integer
"
,
406
actions
=
function
(
n
)
407
getnaturaldimensions
(
n
)
408
context
.
lastnaturalboxwd
(
false
)
409
end
410
}
411 412
implement
{
413
name
=
"
getnaturalwd
"
,
414
arguments
=
"
integer
"
,
415
actions
=
function
(
n
)
416
local
w
=
0
417
local
h
=
0
418
local
d
=
0
419
local
l
=
getlist
(
getbox
(
n
)
)
420
if
l
then
421
w
,
h
,
d
=
getdimensions
(
l
)
422
end
423
context
(
"
\\dimexpr%i\\scaledpoint\\relax
"
,
w
)
424
end
425
}
426 427
local
function
setboxtonaturalwd
(
n
)
428
local
old
=
takebox
(
n
)
429
local
new
=
hpack
(
getlist
(
old
)
)
430
setlist
(
old
,
nil
)
431
flush_node
(
old
)
432
setbox
(
n
,
new
)
433
end
434 435
implement
{
436
name
=
"
setnaturalwd
"
,
437
arguments
=
"
integer
"
,
438
actions
=
setboxtonaturalwd
439
}
440 441
nodes
.
setboxtonaturalwd
=
setboxtonaturalwd
442 443
local
doifelse
=
commands
.
doifelse
444 445
do
446 447
local
dirvalues
=
nodes
.
dirvalues
448
local
lefttoright_code
=
dirvalues
.
lefttoright
449
local
righttoleft_code
=
dirvalues
.
righttoleft
450 451
local
function
firstdirinbox
(
n
)
452
local
b
=
getbox
(
n
)
453
if
b
then
454
local
l
=
getlist
(
b
)
455
if
l
then
456
for
d
in
nextdir
,
l
do
457
return
getdirection
(
d
)
458
end
459
for
h
in
nexthlist
,
l
do
460
return
getdirection
(
h
)
461
end
462
end
463
end
464
return
lefttoright_code
465
end
466 467
nodes
.
firstdirinbox
=
firstdirinbox
468 469
implement
{
470
name
=
"
doifelserighttoleftinbox
"
,
471
arguments
=
"
integer
"
,
472
actions
=
function
(
n
)
473
doifelse
(
firstdirinbox
(
n
)
=
=
righttoleft_code
)
474
end
475
}
476 477
end
478 479
-- new (handy for mp) .. might move to its own module
480 481
do
482 483
local
nuts
=
nodes
.
nuts
484
local
tonode
=
nuts
.
tonode
485
local
takebox
=
nuts
.
takebox
486
local
flush_list
=
nuts
.
flush_list
487
local
copy_list
=
nuts
.
copy_list
488
local
getwhd
=
nuts
.
getwhd
489
local
setbox
=
nuts
.
setbox
490
local
new_hlist
=
nuts
.
pool
.
hlist
491 492
local
boxes
=
{
}
493
nodes
.
boxes
=
boxes
494
local
cache
=
table
.
setmetatableindex
(
"
table
"
)
495
local
report
=
logs
.
reporter
(
"
boxes
"
,
"
cache
"
)
496
local
trace
=
false
497 498
trackers
.
register
(
"
nodes.boxes
"
,
function
(
v
)
trace
=
v
end
)
499 500
function
boxes
.
save
(
category
,
name
,
b
)
501
name
=
tonumber
(
name
)
or
name
502
local
b
=
takebox
(
b
)
503
if
trace
then
504
report
(
"
category %a, name %a, %s (%s)
"
,
category
,
name
,
"
save
"
,
b
and
"
content
"
or
"
empty
"
)
505
end
506
cache
[
category
]
[
name
]
=
b
or
false
507
end
508 509
function
boxes
.
savenode
(
category
,
name
,
n
)
510
name
=
tonumber
(
name
)
or
name
511
if
trace
then
512
report
(
"
category %a, name %a, %s (%s)
"
,
category
,
name
,
"
save
"
,
n
and
"
content
"
or
"
empty
"
)
513
end
514
cache
[
category
]
[
name
]
=
tonut
(
n
)
or
false
515
end
516 517
function
boxes
.
found
(
category
,
name
)
518
name
=
tonumber
(
name
)
or
name
519
return
cache
[
category
]
[
name
]
and
true
or
false
520
end
521 522
function
boxes
.
direct
(
category
,
name
,
copy
)
523
name
=
tonumber
(
name
)
or
name
524
local
c
=
cache
[
category
]
525
local
b
=
c
[
name
]
526
if
not
b
then
527
-- do nothing, maybe trace
528
elseif
copy
then
529
b
=
copy_list
(
b
)
530
else
531
c
[
name
]
=
false
532
end
533
if
trace
then
534
report
(
"
category %a, name %a, %s (%s)
"
,
category
,
name
,
"
direct
"
,
b
and
"
content
"
or
"
empty
"
)
535
end
536
if
b
then
537
return
tonode
(
b
)
538
end
539
end
540 541
function
boxes
.
restore
(
category
,
name
,
box
,
copy
)
542
name
=
tonumber
(
name
)
or
name
543
local
c
=
cache
[
category
]
544
local
b
=
takebox
(
box
)
545
if
b
then
546
flush_list
(
b
)
547
end
548
local
b
=
c
[
name
]
549
if
not
b
then
550
-- do nothing, maybe trace
551
elseif
copy
then
552
b
=
copy_list
(
b
)
553
else
554
c
[
name
]
=
false
555
end
556
if
trace
then
557
report
(
"
category %a, name %a, %s (%s)
"
,
category
,
name
,
"
restore
"
,
b
and
"
content
"
or
"
empty
"
)
558
end
559
setbox
(
box
,
b
or
nil
)
560
end
561 562
function
boxes
.
dimensions
(
category
,
name
)
563
name
=
tonumber
(
name
)
or
name
564
local
b
=
cache
[
category
]
[
name
]
565
if
b
then
566
return
getwhd
(
b
)
567
else
568
return
0
,
0
,
0
569
end
570
end
571 572
function
boxes
.
reset
(
category
,
name
)
573
name
=
tonumber
(
name
)
or
name
574
local
c
=
cache
[
category
]
575
if
name
and
name
~
=
"
"
then
576
local
b
=
c
[
name
]
577
if
b
then
578
flush_list
(
b
)
579
c
[
name
]
=
false
580
end
581
if
trace
then
582
report
(
"
category %a, name %a, reset
"
,
category
,
name
)
583
end
584
else
585
for
k
,
b
in
next
,
c
do
586
if
b
then
587
flush_list
(
b
)
588
end
589
end
590
cache
[
category
]
=
{
}
591
if
trace
then
592
report
(
"
category %a, reset
"
,
category
)
593
end
594
end
595
end
596 597
implement
{
598
name
=
"
putboxincache
"
,
599
arguments
=
{
"
string
"
,
"
string
"
,
"
integer
"
}
,
600
actions
=
boxes
.
save
,
601
}
602 603
implement
{
604
name
=
"
getboxfromcache
"
,
605
arguments
=
{
"
string
"
,
"
string
"
,
"
integer
"
}
,
606
actions
=
boxes
.
restore
,
607
}
608 609
implement
{
610
name
=
"
directboxfromcache
"
,
611
arguments
=
"
2 strings
"
,
612
actions
=
{
boxes
.
direct
,
context
}
,
613
-- actions = function(category,name) local b = boxes.direct(category,name) if b then context(b) end end,
614
}
615 616
implement
{
617
name
=
"
directcopyboxfromcache
"
,
618
arguments
=
{
"
string
"
,
"
string
"
,
true
}
,
619
actions
=
{
boxes
.
direct
,
context
}
,
620
-- actions = function(category,name) local b = boxes.direct(category,name,true) if b then context(b) end end,
621
}
622 623
implement
{
624
name
=
"
copyboxfromcache
"
,
625
arguments
=
{
"
string
"
,
"
string
"
,
"
integer
"
,
true
}
,
626
actions
=
boxes
.
restore
,
627
}
628 629
implement
{
630
name
=
"
doifelseboxincache
"
,
631
arguments
=
"
2 strings
"
,
632
actions
=
{
boxes
.
found
,
doifelse
}
,
633
}
634 635
implement
{
636
name
=
"
resetboxesincache
"
,
637
arguments
=
"
string
"
,
638
actions
=
boxes
.
reset
,
639
}
640 641
end
642 643
implement
{
644
name
=
"
lastlinewidth
"
,
645
actions
=
function
(
)
646
local
head
=
tex
.
lists
.
page_head
647
-- list dimensions returns 3 value but we take the first
648
context
(
head
and
getdimensions
(
getlist
(
find_tail
(
tonut
(
tex
.
lists
.
page_head
)
)
)
)
or
0
)
649
end
650
}
651 652
implement
{
653
name
=
"
shiftbox
"
,
654
arguments
=
{
"
integer
"
,
"
dimension
"
}
,
655
actions
=
function
(
n
,
d
)
656
setshift
(
getbox
(
n
)
,
d
)
657
end
,
658
}
659 660
implement
{
name
=
"
vpackbox
"
,
arguments
=
"
integer
"
,
actions
=
function
(
n
)
setbox
(
n
,
(
vpack
(
takebox
(
n
)
)
)
)
end
}
661
implement
{
name
=
"
hpackbox
"
,
arguments
=
"
integer
"
,
actions
=
function
(
n
)
setbox
(
n
,
(
hpack
(
takebox
(
n
)
)
)
)
end
}
662 663
implement
{
name
=
"
vpackedbox
"
,
arguments
=
"
integer
"
,
actions
=
function
(
n
)
context
(
vpack
(
takebox
(
n
)
)
)
end
}
664
implement
{
name
=
"
hpackedbox
"
,
arguments
=
"
integer
"
,
actions
=
function
(
n
)
context
(
hpack
(
takebox
(
n
)
)
)
end
}
665 666
implement
{
667
name
=
"
scangivendimensions
"
,
668
public
=
true
,
669
protected
=
true
,
670
arguments
=
{
671
{
672
{
"
width
"
,
"
dimension
"
}
,
673
{
"
height
"
,
"
dimension
"
}
,
674
{
"
depth
"
,
"
dimension
"
}
,
675
}
,
676
}
,
677
actions
=
function
(
t
)
678
texsetdimen
(
"
givenwidth
"
,
t
.
width
or
0
)
679
texsetdimen
(
"
givenheight
"
,
t
.
height
or
0
)
680
texsetdimen
(
"
givendepth
"
,
t
.
depth
or
0
)
681
end
,
682
}
683 684
local
function
stripglue
(
list
)
685
local
done
=
false
686
local
first
=
list
687
while
first
do
688
local
id
=
getid
(
first
)
689
if
id
=
=
glue_code
or
id
=
=
penalty_code
then
690
first
=
getnext
(
first
)
691
else
692
break
693
end
694
end
695
if
first
and
first
~
=
list
then
696
-- we have discardables
697
setsplit
(
getprev
(
first
)
,
first
)
698
flush_list
(
list
)
699
list
=
first
700
done
=
true
701
end
702
if
list
then
703
local
tail
=
findtail
(
list
)
704
local
last
=
tail
705
while
last
do
706
local
id
=
getid
(
last
)
707
if
id
=
=
glue_code
or
id
=
=
penalty_code
then
708
last
=
getprev
(
last
)
709
else
710
break
711
end
712
end
713
if
last
~
=
tail
then
714
-- we have discardables
715
flush_list
(
getnext
(
last
)
)
716
setnext
(
last
)
717
done
=
true
718
end
719
end
720
return
list
,
done
721
end
722 723
local
function
limitate
(
t
)
-- don't pack the result !
724
local
text
=
t
.
text
725
if
text
then
726
text
=
tonut
(
text
)
727
else
728
return
729
end
730
local
sentinel
=
t
.
sentinel
731
if
sentinel
then
732
sentinel
=
tonut
(
sentinel
)
733
local
s
=
getlist
(
sentinel
)
734
setlist
(
sentinel
)
735
free
(
sentinel
)
736
sentinel
=
s
737
else
738
return
tonode
(
text
)
739
end
740
local
width
=
getwidth
(
text
)
741
local
list
=
getlist
(
text
)
742
local
done
=
false
743
if
t
.
strip
then
744
list
,
done
=
stripglue
(
list
)
745
if
not
list
then
746
setlist
(
text
)
747
setwidth
(
text
,
0
)
748
return
text
749
elseif
done
then
750
width
=
getdimensions
(
list
)
751
setlist
(
text
,
list
)
752
end
753
end
754
local
left
=
t
.
left
or
0
755
local
right
=
t
.
right
or
0
756
if
left
+
right
<
width
then
757
local
last
=
nil
758
local
first
=
nil
759
local
maxleft
=
left
760
local
maxright
=
right
761
local
swidth
=
getwidth
(
sentinel
)
762
if
maxright
>
0
then
763
maxleft
=
maxleft
-
swidth
/
2
764
maxright
=
maxright
-
swidth
/
2
765
else
766
maxleft
=
maxleft
-
swidth
767
end
768
for
n
in
traverse_id
(
glue_code
,
list
)
do
769
local
width
=
getdimensions
(
list
,
n
)
770
if
width
>
maxleft
then
771
if
not
last
then
772
last
=
n
773
end
774
break
775
else
776
last
=
n
777
end
778
end
779
if
last
and
maxright
>
0
then
780
for
n
in
traverse_id
(
glue_code
,
last
)
do
781
local
width
=
getdimensions
(
n
)
782
if
width
<
maxright
then
783
first
=
n
784
break
785
else
786
first
=
n
787
end
788
end
789
end
790
if
last
then
791
local
rest
=
getnext
(
last
)
792
if
rest
then
793
local
tail
=
findtail
(
sentinel
)
794
if
first
and
getid
(
first
)
=
=
glue_code
and
getid
(
tail
)
=
=
glue_code
then
795
setwidth
(
first
,
0
)
796
end
797
if
last
and
getid
(
last
)
=
=
glue_code
and
getid
(
sentinel
)
=
=
glue_code
then
798
setwidth
(
last
,
0
)
799
end
800
if
first
and
first
~
=
last
then
801
local
prev
=
getprev
(
first
)
802
if
prev
then
803
setnext
(
prev
)
804
end
805
setlink
(
tail
,
first
)
806
end
807
setlink
(
last
,
sentinel
)
808
setprev
(
rest
)
809
flush_list
(
rest
)
810
end
811
end
812
end
813
setlist
(
text
)
814
free
(
text
)
815
return
tonode
(
list
)
816
end
817 818
implement
{
819
name
=
"
limitated
"
,
820
public
=
true
,
821
protected
=
true
,
822
arguments
=
{
823
{
824
{
"
left
"
,
"
dimension
"
}
,
825
{
"
right
"
,
"
dimension
"
}
,
826
{
"
text
"
,
"
hbox
"
}
,
827
{
"
sentinel
"
,
"
hbox
"
}
,
828
{
"
strip
"
,
"
boolean
"
}
,
829
}
830
}
,
831
actions
=
function
(
t
)
832
context
.
dontleavehmode
(
)
833
context
(
limitate
(
t
)
)
834
end
,
835
}
836 837
if
CONTEXTLMTXMODE
>
0
then
838 839
implement
{
840
name
=
"
widthuptohere
"
,
841
public
=
true
,
842
protected
=
true
,
843
value
=
true
,
844
actions
=
function
(
)
845
local
n
=
texgetnest
(
)
846
local
w
=
0
847
if
n
.
mode
=
=
hmode_code
then
848
local
h
=
hpack
(
getnext
(
tonut
(
n
.
head
)
)
)
849
w
=
getwidth
(
h
)
850
setlist
(
h
)
851
free
(
h
)
852
end
853
return
tokens
.
values
.
dimension
,
w
854
end
,
855
}
856 857
end
858 859
implement
{
860
name
=
"
doifelseindented
"
,
861
public
=
true
,
862
protected
=
true
,
863
actions
=
function
(
)
864
local
n
=
texgetnest
(
)
865
local
b
=
false
866
if
n
.
mode
=
=
hmode_code
then
867
n
=
tonut
(
n
.
head
)
868
while
n
do
869
n
=
getnext
(
n
)
870
if
n
then
871
local
id
=
getid
(
n
)
872
if
id
=
=
hlist_code
then
873
if
getsubtype
(
n
)
=
=
indent_code
then
874
b
=
getwidth
(
n
)
>
0
875
break
876
end
877
elseif
id
~
=
localpar_code
then
878
break
879
end
880
end
881
end
882
end
883
commands
.
doifelse
(
b
)
884
end
,
885
}
886 887
implement
{
888
name
=
"
noflinesinbox
"
,
889
public
=
true
,
890
protected
=
false
,
891
arguments
=
"
integer
"
,
892
actions
=
function
(
n
)
893
local
c
=
0
894
local
b
=
getbox
(
n
)
895
if
b
then
896
b
=
getlist
(
b
)
897
if
b
then
898
for
n
,
id
in
traverse
(
b
)
do
899
if
id
=
=
hlist_code
or
id
=
=
vlist_code
then
900
c
=
c
+
1
901
end
902
end
903
end
904
end
905
context
(
c
)
906
end
,
907
}
908