typo-rub.lua /size: 11 Kb    last modification: 2021-10-28 13:50
1
if
not
modules
then
modules
=
{
}
end
modules
[
'
typo-rub
'
]
=
{
2
version
=
1
.
001
,
3
comment
=
"
companion to typo-rub.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
-- todo: recycle slots better
10
-- todo: hoffset
11
-- todo: auto-increase line height
12
-- todo: only hpack when start <> stop
13 14
-- A typical bit of afternoon hackery ... with some breaks for watching
15
-- Ghost-Note on youtube (Robert Searight and Nate Werth) ... which expands
16
-- my to-be-had cd/dvd list again.
17 18
local
lpegmatch
=
lpeg
.
match
19
local
utfcharacters
=
utf
.
characters
20
local
setmetatableindex
=
table
.
setmetatableindex
21 22
local
variables
=
interfaces
.
variables
23
local
implement
=
interfaces
.
implement
24 25
local
texsetattribute
=
tex
.
setattribute
26 27
local
v_flushleft
=
variables
.
flushleft
28
local
v_middle
=
variables
.
middle
29
local
v_flushright
=
variables
.
flushright
30
local
v_yes
=
variables
.
yes
31
local
v_no
=
variables
.
no
32
local
v_auto
=
variables
.
auto
33 34
local
nuts
=
nodes
.
nuts
35 36
local
getid
=
nuts
.
getid
37
local
getsubtype
=
nuts
.
getsubtype
38
local
getattr
=
nuts
.
getattr
39
local
setattr
=
nuts
.
setattr
40
local
getnext
=
nuts
.
getnext
41
local
setnext
=
nuts
.
setnext
42
local
getprev
=
nuts
.
getprev
43
local
setprev
=
nuts
.
setprev
44
local
setlink
=
nuts
.
setlink
45
local
getlist
=
nuts
.
getlist
46
local
setlist
=
nuts
.
setlist
47
local
setshift
=
nuts
.
setshift
48
local
getwidth
=
nuts
.
getwidth
49
local
setwidth
=
nuts
.
setwidth
50 51
local
hpack
=
nuts
.
hpack
52
local
takebox
=
nuts
.
takebox
53 54
local
nexthlist
=
nuts
.
traversers
.
hlist
55
local
nextvlist
=
nuts
.
traversers
.
vlist
56 57
local
nodecodes
=
nodes
.
nodecodes
58
local
glyph_code
=
nodecodes
.
glyph
59
local
disc_code
=
nodecodes
.
disc
60
local
kern_code
=
nodecodes
.
kern
61
local
glue_code
=
nodecodes
.
glue
62
local
penalty_code
=
nodecodes
.
penalty
63
local
hlist_code
=
nodecodes
.
hlist
64
local
vlist_code
=
nodecodes
.
vlist
65
local
par_code
=
nodecodes
.
par
66
local
dir_code
=
nodecodes
.
dir
67 68
local
kerncodes
=
nodes
.
kerncodes
69
local
fontkern_code
=
kerncodes
.
font
70 71
local
nodepool
=
nuts
.
pool
72
local
new_kern
=
nodepool
.
kern
73 74
local
setprop
=
nuts
.
setprop
75
local
getprop
=
nuts
.
getprop
76 77
local
enableaction
=
nodes
.
tasks
.
enableaction
78 79
local
nofrubies
=
0
80
local
rubylist
=
{
}
81 82
local
a_ruby
=
attributes
.
private
(
"
ruby
"
)
83 84
local
rubies
=
{
}
85
typesetters
.
rubies
=
rubies
86 87
local
trace_rubies
=
false
trackers
.
register
(
"
typesetters.rubies
"
,
function
(
v
)
trace_rubies
=
v
end
)
88
local
report_rubies
=
logs
.
reporter
(
"
rubies
"
)
89 90
do
91 92
local
shared
=
nil
93
local
splitter
=
lpeg
.
tsplitat
(
"
|
"
)
94 95
local
function
enable
(
)
96
enableaction
(
"
processors
"
,
"
typesetters.rubies.check
"
)
97
enableaction
(
"
shipouts
"
,
"
typesetters.rubies.attach
"
)
98
enable
=
false
99
end
100 101
local
ctx_setruby
=
context
.
core
.
setruby
102 103
local
function
ruby
(
settings
)
104
local
base
=
settings
.
base
105
local
comment
=
settings
.
comment
106
shared
=
settings
107
local
c
=
lpegmatch
(
splitter
,
comment
)
108
if
#
c
=
=
1
then
109
ctx_setruby
(
base
,
comment
)
110
if
trace_rubies
then
111
report_rubies
(
"
- %s -> %s
"
,
base
,
comment
)
112
end
113
else
114
local
i
=
0
115
for
b
in
utfcharacters
(
base
)
do
116
i
=
i
+
1
117
local
r
=
c
[
i
]
118
if
r
then
119
ctx_setruby
(
b
,
r
)
120
if
trace_rubies
then
121
report_rubies
(
"
%i: %s -> %s
"
,
i
,
b
,
r
)
122
end
123
else
124
ctx_setruby
(
b
,
"
"
)
125
if
trace_rubies
then
126
report_rubies
(
"
%i: %s
"
,
i
,
b
)
127
end
128
end
129
end
130
end
131
if
enable
then
132
enable
(
)
133
end
134
end
135 136
local
function
startruby
(
settings
)
137
shared
=
settings
138
if
enable
then
139
enable
(
)
140
end
141
end
142 143
implement
{
144
name
=
"
ruby
"
,
145
actions
=
ruby
,
146
arguments
=
{
147
{
148
{
"
align
"
}
,
149
{
"
stretch
"
}
,
150
{
"
hoffset
"
,
"
dimension
"
}
,
151
{
"
voffset
"
,
"
dimension
"
}
,
152
{
"
comment
"
}
,
153
{
"
base
"
}
,
154
}
155
}
,
156
}
157 158
implement
{
159
name
=
"
startruby
"
,
160
actions
=
startruby
,
161
arguments
=
{
162
{
163
{
"
align
"
}
,
164
{
"
stretch
"
}
,
165
{
"
hoffset
"
,
"
dimension
"
}
,
166
{
"
voffset
"
,
"
dimension
"
}
,
167
}
168
}
,
169
}
170 171
local
function
setruby
(
n
,
m
)
172
nofrubies
=
nofrubies
+
1
173
local
r
=
takebox
(
n
)
174
rubylist
[
nofrubies
]
=
setmetatableindex
(
{
175
text
=
r
,
176
width
=
getwidth
(
r
)
,
177
basewidth
=
0
,
178
start
=
false
,
179
stop
=
false
,
180
}
,
shared
)
181
texsetattribute
(
a_ruby
,
nofrubies
)
182
end
183 184
implement
{
185
name
=
"
setruby
"
,
186
actions
=
setruby
,
187
arguments
=
"
integer
"
,
188
}
189 190
end
191 192
function
rubies
.
check
(
head
)
193
local
current
=
head
194
local
start
=
nil
195
local
stop
=
nil
196
local
found
=
nil
197 198
local
function
flush
(
where
)
199
local
r
=
rubylist
[
found
]
200
if
r
then
201
local
prev
=
getprev
(
start
)
202
local
next
=
getnext
(
stop
)
203
setprev
(
start
)
204
setnext
(
stop
)
205
local
h
=
hpack
(
start
)
206
if
start
=
=
head
then
207
head
=
h
208
else
209
setlink
(
prev
,
h
)
210
end
211
setlink
(
h
,
next
)
212
local
bwidth
=
getwidth
(
h
)
213
local
rwidth
=
r
.
width
214
r
.
basewidth
=
bwidth
215
r
.
start
=
start
216
r
.
stop
=
stop
217
setprop
(
h
,
"
ruby
"
,
found
)
218
if
rwidth
>
bwidth
then
219
-- ruby is wider
220
setwidth
(
h
,
rwidth
)
221
end
222
end
223
end
224 225
while
current
do
226
local
nx
=
getnext
(
current
)
227
local
id
=
getid
(
current
)
228
if
id
=
=
glyph_code
then
229
local
a
=
getattr
(
current
,
a_ruby
)
230
if
not
a
then
231
if
found
then
232
flush
(
"
flush 1
"
)
233
found
=
nil
234
end
235
elseif
a
=
=
found
then
236
stop
=
current
237
else
238
if
found
then
239
flush
(
"
flush 2
"
)
240
end
241
found
=
a
242
start
=
current
243
stop
=
current
244
end
245
-- go on
246
elseif
id
=
=
kern_code
and
getsubtype
(
current
,
fontkern_code
)
then
247
-- go on
248
elseif
found
and
id
=
=
disc_code
then
249
-- go on (todo: look into disc)
250
elseif
found
then
251
flush
(
"
flush 3
"
)
252
found
=
nil
253
end
254
current
=
nx
255
end
256
if
found
then
257
flush
(
"
flush 4
"
)
258
end
259
return
head
,
true
-- no need for true
260
end
261 262
local
attach
263 264
local
function
whatever
(
current
)
265
local
a
=
getprop
(
current
,
"
ruby
"
)
266
if
a
then
267
local
ruby
=
rubylist
[
a
]
268
local
align
=
ruby
.
align
or
v_middle
269
local
stretch
=
ruby
.
stretch
or
v_no
270
local
hoffset
=
ruby
.
hoffset
or
0
271
local
voffset
=
ruby
.
voffset
or
0
272
local
start
=
ruby
.
start
273
local
stop
=
ruby
.
stop
274
local
text
=
ruby
.
text
275
local
rwidth
=
ruby
.
width
276
local
bwidth
=
ruby
.
basewidth
277
local
delta
=
rwidth
-
bwidth
278
setwidth
(
text
,
0
)
279
if
voffset
~
=
0
then
280
setshift
(
text
,
voffset
)
281
end
282
-- center them
283
if
delta
>
0
then
284
-- ruby is wider
285
if
stretch
=
=
v_yes
then
286
setlink
(
text
,
start
)
287
while
start
and
start
~
=
stop
do
288
local
s
=
nodepool
.
stretch
(
)
289
local
n
=
getnext
(
start
)
290
setlink
(
start
,
s
,
n
)
291
start
=
n
292
end
293
text
=
hpack
(
text
,
rwidth
,
"
exactly
"
)
294
else
295
local
left
=
new_kern
(
delta
/
2
)
296
local
right
=
new_kern
(
delta
/
2
)
297
setlink
(
text
,
left
,
start
)
298
setlink
(
stop
,
right
)
299
end
300
setlist
(
current
,
text
)
301
elseif
delta
<
0
then
302
-- ruby is narrower
303
if
align
=
=
v_auto
then
304
local
l
=
true
305
local
c
=
getprev
(
current
)
306
while
c
do
307
local
id
=
getid
(
c
)
308
if
id
=
=
glue_code
or
id
=
=
penalty_code
or
id
=
=
kern_code
then
309
-- go on
310
elseif
id
=
=
hlist_code
and
getwidth
(
c
)
=
=
0
then
311
-- go on
312
elseif
id
=
=
whatsit_code
or
id
=
=
par_code
or
id
=
=
dir_code
then
313
-- go on
314
else
315
l
=
false
316
break
317
end
318
c
=
getprev
(
c
)
319
end
320
local
r
=
true
321
local
c
=
getnext
(
current
)
322
while
c
do
323
local
id
=
getid
(
c
)
324
if
id
=
=
glue_code
or
id
=
=
penalty_code
or
id
=
=
kern_code
then
325
-- go on
326
elseif
id
=
=
hlist_code
and
getwidth
(
c
)
=
=
0
then
327
-- go on
328
else
329
r
=
false
330
break
331
end
332
c
=
getnext
(
c
)
333
end
334
if
l
and
not
r
then
335
align
=
v_flushleft
336
elseif
r
and
not
l
then
337
align
=
v_flushright
338
else
339
align
=
v_middle
340
end
341
end
342
if
align
=
=
v_flushleft
then
343
setlink
(
text
,
start
)
344
setlist
(
current
,
text
)
345
elseif
align
=
=
v_flushright
then
346
local
left
=
new_kern
(
-
delta
)
347
local
right
=
new_kern
(
delta
)
348
setlink
(
left
,
text
,
right
,
start
)
349
setlist
(
current
,
left
)
350
else
351
local
left
=
new_kern
(
-
delta
/
2
)
352
local
right
=
new_kern
(
delta
/
2
)
353
setlink
(
left
,
text
,
right
,
start
)
354
setlist
(
current
,
left
)
355
end
356
else
357
setlink
(
text
,
start
)
358
setlist
(
current
,
text
)
359
end
360
setprop
(
current
,
"
ruby
"
,
false
)
361
rubylist
[
a
]
=
nil
362
else
363
local
list
=
getlist
(
current
)
364
if
list
then
365
attach
(
list
)
366
end
367
end
368
end
369 370
attach
=
function
(
head
)
371
for
current
in
nexthlist
,
head
do
372
whatever
(
current
)
373
end
374
for
current
in
nextvlist
,
head
do
375
whatever
(
current
)
376
end
377
return
head
378
end
379 380
rubies
.
attach
=
attach
381 382
-- for now there is no need to be compact
383 384
-- local data = { }
385
-- rubies.data = data
386
--
387
-- function rubies.define(settings)
388
-- data[#data+1] = settings
389
-- return #data
390
-- end
391
--
392
-- implement {
393
-- name = "defineruby",
394
-- actions = { rubies.define, context },
395
-- arguments = {
396
-- {
397
-- { "align" },
398
-- { "stretch" },
399
-- }
400
-- }
401
-- }
402