typo-brk.lua /size: 15 Kb    last modification: 2020-07-01 14:35
1
if
not
modules
then
modules
=
{
}
end
modules
[
'
typo-brk
'
]
=
{
2
version
=
1
.
001
,
3
comment
=
"
companion to typo-brk.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 code dates from the beginning and is kind of experimental; it
10
-- will be optimized and improved soon
11 12
local
next
,
type
,
tonumber
,
tostring
=
next
,
type
,
tonumber
,
tostring
13
local
utfbyte
,
utfchar
=
utf
.
byte
,
utf
.
char
14
local
format
=
string
.
format
15 16
local
trace_breakpoints
=
false
trackers
.
register
(
"
typesetters.breakpoints
"
,
function
(
v
)
trace_breakpoints
=
v
end
)
17 18
local
report_breakpoints
=
logs
.
reporter
(
"
typesetting
"
,
"
breakpoints
"
)
19 20
local
nodes
,
node
=
nodes
,
node
21 22
local
settings_to_array
=
utilities
.
parsers
.
settings_to_array
23 24
local
nuts
=
nodes
.
nuts
25
local
tonut
=
nuts
.
tonut
26 27
local
getnext
=
nuts
.
getnext
28
local
getprev
=
nuts
.
getprev
29
local
getboth
=
nuts
.
getboth
30
local
getsubtype
=
nuts
.
getsubtype
31
local
getfont
=
nuts
.
getfont
32
local
getid
=
nuts
.
getid
33
----- getattr = nuts.getattr
34
local
getattrlist
=
nuts
.
getattrlist
35
local
takeattr
=
nuts
.
takeattr
36
local
getlang
=
nuts
.
getlang
37
local
isglyph
=
nuts
.
isglyph
38 39
local
setattr
=
nuts
.
setattr
40
local
setattrlist
=
nuts
.
setattrlist
41
local
setlink
=
nuts
.
setlink
42
local
setchar
=
nuts
.
setchar
43
local
setdisc
=
nuts
.
setdisc
44
local
setnext
=
nuts
.
setnext
45
local
setprev
=
nuts
.
setprev
46
local
setboth
=
nuts
.
setboth
47
local
setsubtype
=
nuts
.
setsubtype
48 49
local
copy_node
=
nuts
.
copy_node
50
local
copy_node_list
=
nuts
.
copy_list
51
local
flush_node
=
nuts
.
flush_node
52
local
insert_node_before
=
nuts
.
insert_before
53
local
insert_node_after
=
nuts
.
insert_after
54
local
remove_node
=
nuts
.
remove
55
local
end_of_math
=
nuts
.
end_of_math
56 57
local
tonodes
=
nuts
.
tonodes
58 59
local
texsetattribute
=
tex
.
setattribute
60
local
unsetvalue
=
attributes
.
unsetvalue
61 62
local
nodepool
=
nuts
.
pool
63
local
enableaction
=
nodes
.
tasks
.
enableaction
64 65
local
v_reset
=
interfaces
.
variables
.
reset
66
local
v_yes
=
interfaces
.
variables
.
yes
67 68
local
implement
=
interfaces
.
implement
69 70
local
new_penalty
=
nodepool
.
penalty
71
local
new_glue
=
nodepool
.
glue
72
local
new_disc
=
nodepool
.
disc
73
local
new_wordboundary
=
nodepool
.
wordboundary
74 75
local
nodecodes
=
nodes
.
nodecodes
76
local
kerncodes
=
nodes
.
kerncodes
77 78
local
kern_code
=
nodecodes
.
kern
79
local
math_code
=
nodecodes
.
math
80 81
local
fontkern_code
=
kerncodes
.
fontkern
82
local
italickern_code
=
kerncodes
.
italiccorrection
83 84
local
is_letter
=
characters
.
is_letter
85 86
local
typesetters
=
typesetters
87 88
typesetters
.
breakpoints
=
typesetters
.
breakpoints
or
{
}
89
local
breakpoints
=
typesetters
.
breakpoints
90 91
breakpoints
.
mapping
=
breakpoints
.
mapping
or
{
}
92
breakpoints
.
numbers
=
breakpoints
.
numbers
or
{
}
93 94
breakpoints
.
methods
=
breakpoints
.
methods
or
{
}
95
local
methods
=
breakpoints
.
methods
96 97
local
a_breakpoints
=
attributes
.
private
(
"
breakpoint
"
)
98 99
storage
.
register
(
"
typesetters/breakpoints/mapping
"
,
breakpoints
.
mapping
,
"
typesetters.breakpoints.mapping
"
)
100 101
local
mapping
=
breakpoints
.
mapping
102
local
numbers
=
breakpoints
.
mapping
103 104
for
i
=
1
,
#
mapping
do
105
local
m
=
mapping
[
i
]
106
numbers
[
m
.
name
]
=
m
107
end
108 109
-- this needs a cleanup ... maybe make all of them disc nodes
110 111
-- todo: use boundaries
112 113
local
function
insert_break
(
head
,
start
,
stop
,
before
,
after
,
kern
)
114
if
not
kern
then
115
local
p
=
new_penalty
(
before
)
116
local
g
=
new_glue
(
)
117
setattrlist
(
p
,
start
)
118
setattrlist
(
g
,
start
)
119
insert_node_before
(
head
,
start
,
p
)
120
insert_node_before
(
head
,
start
,
g
)
121
end
122
local
p
=
new_penalty
(
after
)
123
local
g
=
new_glue
(
)
124
setattrlist
(
p
,
start
)
125
setattrlist
(
g
,
start
)
126
insert_node_after
(
head
,
stop
,
g
)
127
insert_node_after
(
head
,
stop
,
p
)
128
end
129 130
methods
[
1
]
=
function
(
head
,
start
,
stop
,
settings
,
kern
)
131
local
p
,
n
=
getboth
(
stop
)
132
if
p
and
n
then
133
insert_break
(
head
,
start
,
stop
,
10000
,
0
,
kern
)
134
end
135
return
head
,
stop
136
end
137 138
methods
[
6
]
=
function
(
head
,
start
,
stop
,
settings
,
kern
)
139
local
p
=
getprev
(
start
)
140
local
n
=
getnext
(
stop
)
141
if
p
and
n
then
142
if
kern
then
143
insert_break
(
head
,
start
,
stop
,
10000
,
0
,
kern
)
144
else
145
local
l
=
new_wordboundary
(
)
146
local
d
=
new_disc
(
)
147
local
r
=
new_wordboundary
(
)
148
setattrlist
(
d
,
start
)
-- otherwise basemode is forced and we crash
149
setlink
(
p
,
l
,
d
,
r
,
n
)
150
if
start
=
=
stop
then
151
setboth
(
start
)
152
setdisc
(
d
,
start
,
nil
,
copy_node
(
start
)
)
153
else
154
setprev
(
start
)
155
setnext
(
stop
)
156
setdisc
(
d
,
start
,
nil
,
copy_node_list
(
start
)
)
157
end
158
stop
=
r
159
end
160
end
161
return
head
,
stop
162
end
163 164
methods
[
2
]
=
function
(
head
,
start
)
-- ( => (-
165
local
p
,
n
=
getboth
(
start
)
166
if
p
and
n
then
167
local
replace
168
head
,
start
,
replace
=
remove_node
(
head
,
start
)
169
local
post
=
copy_node
(
replace
)
170
local
hyphen
=
copy_node
(
post
)
171
setchar
(
hyphen
,
languages
.
prehyphenchar
(
getlang
(
post
)
)
)
172
setlink
(
post
,
hyphen
)
173
head
,
start
=
insert_node_before
(
head
,
start
,
new_disc
(
nil
,
post
,
replace
)
)
174
setattrlist
(
start
,
replace
)
175
insert_break
(
head
,
start
,
start
,
10000
,
10000
)
176
end
177
return
head
,
start
178
end
179 180
methods
[
3
]
=
function
(
head
,
start
)
-- ) => -)
181
local
p
,
n
=
getboth
(
start
)
182
if
p
and
n
then
183
local
replace
184
head
,
start
,
replace
=
remove_node
(
head
,
start
)
185
local
pre
=
copy_node
(
replace
)
186
local
hyphen
=
copy_node
(
pre
)
187
setchar
(
hyphen
,
languages
.
prehyphenchar
(
getlang
(
pre
)
)
)
188
setlink
(
hyphen
,
pre
)
189
head
,
start
=
insert_node_before
(
head
,
start
,
new_disc
(
hyphen
,
nil
,
replace
)
)
-- so not pre !
190
setattrlist
(
start
,
tmp
)
191
insert_break
(
head
,
start
,
start
,
10000
,
10000
)
192
end
193
return
head
,
start
194
end
195 196
methods
[
4
]
=
function
(
head
,
start
)
-- - => - - -
197
local
p
,
n
=
getboth
(
start
)
198
if
p
and
n
then
199
local
tmp
200
head
,
start
,
tmp
=
remove_node
(
head
,
start
)
201
head
,
start
=
insert_node_before
(
head
,
start
,
new_disc
(
)
)
202
setattrlist
(
start
,
tmp
)
203
setdisc
(
start
,
copy_node
(
tmp
)
,
copy_node
(
tmp
)
,
tmp
)
204
insert_break
(
head
,
start
,
start
,
10000
,
10000
)
205
end
206
return
head
,
start
207
end
208 209
methods
[
5
]
=
function
(
head
,
start
,
stop
,
settings
)
-- x => p q r
210
local
p
,
n
=
getboth
(
start
)
211
if
p
and
n
then
212
local
tmp
213
head
,
start
,
tmp
=
remove_node
(
head
,
start
)
214
head
,
start
=
insert_node_before
(
head
,
start
,
new_disc
(
)
)
215
local
attr
=
getattrlist
(
tmp
)
216
local
font
=
getfont
(
tmp
)
217
local
left
=
settings
.
left
218
local
right
=
settings
.
right
219
local
middle
=
settings
.
middle
220
if
left
then
221
left
=
tonodes
(
tostring
(
left
)
,
font
,
attr
)
222
end
223
if
right
then
224
right
=
tonodes
(
tostring
(
right
)
,
font
,
attr
)
225
end
226
if
middle
then
227
middle
=
tonodes
(
tostring
(
middle
)
,
font
,
attr
)
228
end
229
setdisc
(
start
,
left
,
right
,
middle
)
230
setattrlist
(
start
,
attr
)
231
flush_node
(
tmp
)
232
insert_break
(
head
,
start
,
start
,
10000
,
10000
)
233
end
234
return
head
,
start
235
end
236 237
-- we know we have a limited set
238
-- what if characters are replaced by the font handler
239
-- do we need to go into disc nodes (or do it as first step but then we need a pre/post font handler)
240 241
function
breakpoints
.
handler
(
head
)
242
local
done
=
false
243
local
attr
=
nil
244
local
map
=
nil
245
local
current
=
head
246
while
current
do
247
local
char
,
id
=
isglyph
(
current
)
248
if
char
then
249
-- local a = getattr(current,a_breakpoints)
250
local
a
=
takeattr
(
current
,
a_breakpoints
)
251
if
a
and
a
>
0
then
252
if
a
~
=
attr
then
253
local
data
=
mapping
[
a
]
254
if
data
then
255
map
=
data
.
characters
256
else
257
map
=
nil
258
end
259
attr
=
a
260
end
261
if
map
then
262
local
cmap
=
map
[
char
]
263
if
cmap
then
264
-- setattr(current,a_breakpoints,unsetvalue) -- should not be needed
265
-- for now we collect but when found ok we can move the handler here
266
-- although it saves nothing in terms of performance
267
local
lang
=
getlang
(
current
)
268
local
smap
=
lang
and
lang
>
=
0
and
lang
<
0x7FFF
and
(
cmap
[
languages
.
numbers
[
lang
]
]
or
cmap
[
"
"
]
)
269
if
smap
then
270
local
skip
=
smap
.
skip
271
local
start
=
current
272
local
stop
=
current
273
current
=
getnext
(
current
)
274
if
skip
then
275
while
current
do
276
local
c
=
isglyph
(
current
)
277
if
c
=
=
char
then
278
stop
=
current
279
current
=
getnext
(
current
)
280
else
281
break
282
end
283
end
284
end
285
local
d
=
{
start
,
stop
,
cmap
,
smap
,
char
}
286
if
done
then
287
done
[
#
done
+
1
]
=
d
288
else
289
done
=
{
d
}
290
end
291
else
292
current
=
getnext
(
current
)
293
end
294
else
295
current
=
getnext
(
current
)
296
end
297
else
298
current
=
getnext
(
current
)
299
end
300
else
301
current
=
getnext
(
current
)
302
end
303
elseif
id
=
=
math_code
then
304
attr
=
nil
305
current
=
end_of_math
(
current
)
306
if
current
then
307
current
=
getnext
(
current
)
308
end
309
else
310
current
=
getnext
(
current
)
311
end
312
end
313
if
not
done
then
314
return
head
315
end
316
-- we have hits
317
-- local numbers = languages.numbers
318
for
i
=
1
,
#
done
do
319
local
data
=
done
[
i
]
320
local
start
=
data
[
1
]
321
local
stop
=
data
[
2
]
322
local
cmap
=
data
[
3
]
323
local
smap
=
data
[
4
]
324
-- we do a sanity check for language
325
-- local lang = getlang(start)
326
-- local smap = lang and lang >= 0 and lang < 0x7FFF and (cmap[numbers[lang]] or cmap[""])
327
-- if smap then
328
local
nleft
=
smap
.
nleft
329
local
cleft
=
0
330
local
prev
=
getprev
(
start
)
331
local
kern
=
nil
332
while
prev
and
nleft
~
=
cleft
do
333
local
char
,
id
=
isglyph
(
prev
)
334
if
char
then
335
if
not
is_letter
[
char
]
then
336
cleft
=
-1
337
break
338
end
339
cleft
=
cleft
+
1
340
prev
=
getprev
(
prev
)
341
elseif
id
=
=
kern_code
then
342
local
s
=
getsubtype
(
prev
)
343
if
s
=
=
fontkern_code
or
s
=
=
italickern_code
then
344
if
cleft
=
=
0
then
345
kern
=
prev
346
prev
=
getprev
(
prev
)
347
else
348
break
349
end
350
else
351
break
352
end
353
else
354
break
355
end
356
end
357
if
nleft
=
=
cleft
then
358
local
nright
=
smap
.
nright
359
local
cright
=
0
360
local
next
=
getnext
(
stop
)
-- getnext(start)
361
while
next
and
nright
~
=
cright
do
362
local
char
,
id
=
isglyph
(
next
)
363
if
char
then
364
if
not
is_letter
[
char
]
then
365
cright
=
-1
366
break
367
end
368
if
cright
=
=
1
and
cmap
[
char
]
then
369
-- let's not make it too messy
370
break
371
end
372
cright
=
cright
+
1
373
next
=
getnext
(
next
)
374
elseif
id
=
=
kern_code
then
375
local
s
=
getsubtype
(
next
)
376
if
s
=
=
fontkern_code
or
s
=
=
italickern_code
then
377
if
cleft
=
=
0
then
378
next
=
getnext
(
next
)
379
else
380
break
381
end
382
else
383
break
384
end
385
else
386
break
387
end
388
end
389
if
nright
=
=
cright
then
390
local
method
=
methods
[
smap
.
type
]
391
if
method
then
392
head
,
start
=
method
(
head
,
start
,
stop
,
smap
,
kern
)
393
end
394
end
395
-- end
396
end
397
end
398
return
head
399
end
400 401
local
enabled
=
false
402 403
function
breakpoints
.
define
(
name
)
404
local
data
=
numbers
[
name
]
405
if
data
then
406
-- error
407
else
408
local
number
=
#
mapping
+
1
409
local
data
=
{
410
name
=
name
,
411
number
=
number
,
412
characters
=
{
}
,
413
}
414
mapping
[
number
]
=
data
415
numbers
[
name
]
=
data
416
end
417
end
418 419
function
breakpoints
.
setreplacement
(
name
,
char
,
language
,
settings
)
420
char
=
utfbyte
(
char
)
421
local
data
=
numbers
[
name
]
422
if
data
then
423
local
characters
=
data
.
characters
424
local
cmap
=
characters
[
char
]
425
if
not
cmap
then
426
cmap
=
{
}
427
characters
[
char
]
=
cmap
428
end
429
local
left
,
right
,
middle
=
settings
.
left
,
settings
.
right
,
settings
.
middle
430
cmap
[
language
or
"
"
]
=
{
431
type
=
tonumber
(
settings
.
type
)
or
1
,
432
nleft
=
tonumber
(
settings
.
nleft
)
or
1
,
433
nright
=
tonumber
(
settings
.
nright
)
or
1
,
434
left
=
left
~
=
"
"
and
left
or
nil
,
435
right
=
right
~
=
"
"
and
right
or
nil
,
436
middle
=
middle
~
=
"
"
and
middle
or
nil
,
437
skip
=
settings
.
range
=
=
v_yes
,
438
}
-- was { type or 1, before or 1, after or 1 }
439
end
440
end
441 442
function
breakpoints
.
set
(
n
)
443
if
n
=
=
v_reset
then
444
n
=
unsetvalue
445
else
446
n
=
mapping
[
n
]
447
if
not
n
then
448
n
=
unsetvalue
449
else
450
if
not
enabled
then
451
if
trace_breakpoints
then
452
report_breakpoints
(
"
enabling breakpoints handler
"
)
453
end
454
enableaction
(
"
processors
"
,
"
typesetters.breakpoints.handler
"
)
455
end
456
n
=
n
.
number
457
end
458
end
459
texsetattribute
(
a_breakpoints
,
n
)
460
end
461 462
-- interface
463 464
implement
{
465
name
=
"
definebreakpoints
"
,
466
actions
=
breakpoints
.
define
,
467
arguments
=
"
string
"
468
}
469 470
implement
{
471
name
=
"
definebreakpoint
"
,
472
actions
=
breakpoints
.
setreplacement
,
473
arguments
=
{
474
"
string
"
,
475
"
string
"
,
476
"
string
"
,
477
{
478
{
"
type
"
,
"
integer
"
}
,
479
{
"
nleft
"
,
"
integer
"
}
,
480
{
"
nright
"
,
"
integer
"
}
,
481
{
"
right
"
}
,
482
{
"
left
"
}
,
483
{
"
middle
"
}
,
484
{
"
range
"
}
,
485
}
486
}
487
}
488 489
implement
{
490
name
=
"
setbreakpoints
"
,
491
actions
=
breakpoints
.
set
,
492
arguments
=
"
string
"
493
}
494