typo-tal.lua /size: 14 Kb    last modification: 2020-07-01 14:35
1
if
not
modules
then
modules
=
{
}
end
modules
[
'
typo-tal
'
]
=
{
2
version
=
1
.
001
,
3
comment
=
"
companion to typo-tal.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
-- I'll make it a bit more efficient and provide named instances too which is needed for
10
-- nested tables.
11
--
12
-- Currently we have two methods: text and number with some downward compatible
13
-- defaulting.
14 15
-- We can speed up by saving the current fontcharacters[font] + lastfont.
16 17
local
next
,
type
,
tonumber
=
next
,
type
,
tonumber
18
local
div
=
math
.
div
19
local
utfbyte
=
utf
.
byte
20 21
local
splitmethod
=
utilities
.
parsers
.
splitmethod
22 23
local
nodecodes
=
nodes
.
nodecodes
24
local
glyph_code
=
nodecodes
.
glyph
25
local
glue_code
=
nodecodes
.
glue
26 27
local
fontcharacters
=
fonts
.
hashes
.
characters
28
----- unicodes = fonts.hashes.unicodes
29
local
categories
=
characters
.
categories
-- nd
30 31
local
variables
=
interfaces
.
variables
32
local
v_text
=
variables
.
text
33
local
v_number
=
variables
.
number
34 35
local
nuts
=
nodes
.
nuts
36
local
tonut
=
nuts
.
tonut
37 38
local
getnext
=
nuts
.
getnext
39
local
getprev
=
nuts
.
getprev
40
local
getboth
=
nuts
.
getboth
41
local
getid
=
nuts
.
getid
42
local
getfont
=
nuts
.
getfont
43
local
getchar
=
nuts
.
getchar
44
local
getattr
=
nuts
.
getattr
45
local
isglyph
=
nuts
.
isglyph
46 47
local
setattr
=
nuts
.
setattr
48
local
setchar
=
nuts
.
setchar
49 50
local
insert_node_before
=
nuts
.
insert_before
51
local
insert_node_after
=
nuts
.
insert_after
52
local
nextglyph
=
nuts
.
traversers
.
glyph
53
local
getdimensions
=
nuts
.
dimensions
54
local
first_glyph
=
nuts
.
first_glyph
55 56
local
setglue
=
nuts
.
setglue
57 58
local
nodepool
=
nuts
.
pool
59
local
new_kern
=
nodepool
.
kern
60 61
local
tracers
=
nodes
.
tracers
62
local
setcolor
=
tracers
.
colors
.
set
63
local
tracedrule
=
tracers
.
pool
.
nuts
.
rule
64 65
local
enableaction
=
nodes
.
tasks
.
enableaction
66 67
local
characteralign
=
{
}
68
typesetters
.
characteralign
=
characteralign
69 70
local
trace_split
=
false
trackers
.
register
(
"
typesetters.characteralign
"
,
function
(
v
)
trace_split
=
true
end
)
71
local
report
=
logs
.
reporter
(
"
aligning
"
)
72 73
local
a_characteralign
=
attributes
.
private
(
"
characteralign
"
)
74
local
a_character
=
attributes
.
private
(
"
characters
"
)
75 76
local
enabled
=
false
77 78
local
datasets
=
false
79 80
local
implement
=
interfaces
.
implement
81 82
local
comma
=
0x002C
83
local
period
=
0x002E
84
local
punctuationspace
=
0x2008
85 86
local
validseparators
=
{
87
[
comma
]
=
true
,
88
[
period
]
=
true
,
89
[
punctuationspace
]
=
true
,
90
}
91 92
local
validsigns
=
{
93
[
0x002B
]
=
0x002B
,
-- plus
94
[
0x002D
]
=
0x2212
,
-- hyphen
95
[
0x00B1
]
=
0x00B1
,
-- plusminus
96
[
0x2212
]
=
0x2212
,
-- minus
97
[
0x2213
]
=
0x2213
,
-- minusplus
98
}
99 100
-- If needed we can have more modes which then also means a faster simple handler
101
-- for non numbers.
102 103
local
function
setcharacteralign
(
column
,
separator
,
before
,
after
)
104
if
not
enabled
then
105
enableaction
(
"
processors
"
,
"
typesetters.characteralign.handler
"
)
106
enabled
=
true
107
end
108
if
not
datasets
then
109
datasets
=
{
}
110
end
111
local
dataset
=
datasets
[
column
]
-- we can use a metatable
112
if
not
dataset
then
113
local
method
,
token
114
if
separator
then
115
method
,
token
=
splitmethod
(
separator
)
116
if
method
and
token
then
117
separator
=
utfbyte
(
token
)
or
comma
118
else
119
separator
=
utfbyte
(
separator
)
or
comma
120
method
=
validseparators
[
separator
]
and
v_number
or
v_text
121
end
122
else
123
separator
=
comma
124
method
=
v_number
125
end
126
local
before
=
tonumber
(
before
)
or
0
127
local
after
=
tonumber
(
after
)
or
0
128
dataset
=
{
129
separator
=
separator
,
130
list
=
{
}
,
131
maxbefore
=
before
,
132
maxafter
=
after
,
133
predefined
=
before
>
0
or
after
>
0
,
134
collected
=
false
,
135
method
=
method
,
136
separators
=
validseparators
,
137
signs
=
validsigns
,
138
}
139
datasets
[
column
]
=
dataset
140
used
=
true
141
end
142
return
dataset
143
end
144 145
local
function
resetcharacteralign
(
)
146
datasets
=
false
147
end
148 149
characteralign
.
setcharacteralign
=
setcharacteralign
150
characteralign
.
resetcharacteralign
=
resetcharacteralign
151 152
implement
{
153
name
=
"
setcharacteralign
"
,
154
actions
=
setcharacteralign
,
155
arguments
=
{
"
integer
"
,
"
string
"
}
156
}
157 158
implement
{
159
name
=
"
setcharacteraligndetail
"
,
160
actions
=
setcharacteralign
,
161
arguments
=
{
"
integer
"
,
"
string
"
,
"
dimension
"
,
"
dimension
"
}
162
}
163 164
implement
{
165
name
=
"
resetcharacteralign
"
,
166
actions
=
resetcharacteralign
167
}
168 169
local
function
traced_kern
(
w
)
170
return
tracedrule
(
w
,
nil
,
nil
,
"
darkgray
"
)
171
end
172 173
function
characteralign
.
handler
(
head
,
where
)
174
if
not
datasets
then
175
return
head
176
end
177
-- local first = first_glyph(head) -- we could do that once
178
local
first
179
for
n
in
nextglyph
,
head
do
180
first
=
n
181
break
182
end
183
if
not
first
then
184
return
head
185
end
186
local
a
=
getattr
(
first
,
a_characteralign
)
187
if
not
a
or
a
=
=
0
then
188
return
head
189
end
190
local
column
=
div
(
a
,
0xFFFF
)
191
local
row
=
a
%
0xFFFF
192
local
dataset
=
datasets
and
datasets
[
column
]
or
setcharacteralign
(
column
)
193
local
separator
=
dataset
.
separator
194
local
list
=
dataset
.
list
195
local
b_start
=
nil
196
local
b_stop
=
nil
197
local
a_start
=
nil
198
local
a_stop
=
nil
199
local
c
=
nil
200
local
current
=
first
201
local
sign
=
nil
202
--
203
local
validseparators
=
dataset
.
separators
204
local
validsigns
=
dataset
.
signs
205
local
method
=
dataset
.
method
206
-- we can think of constraints
207
if
method
=
=
v_number
then
208 209
local
function
bothdigit
(
current
)
-- this could become a helper
210
local
prev
,
next
=
getboth
(
current
)
211
if
next
and
prev
and
getid
(
next
)
=
=
glyph_code
and
getid
(
prev
)
=
=
glyph_code
then
212
local
pchar
=
getchar
(
prev
)
213
local
nchar
=
getchar
(
next
)
214
local
pdata
=
fontcharacters
[
getfont
(
prev
)
]
[
pchar
]
215
local
ndata
=
fontcharacters
[
getfont
(
next
)
]
[
nchar
]
216
local
punicode
=
pdata
and
pdata
.
unicode
or
pchar
-- we ignore tables
217
local
nunicode
=
ndata
and
ndata
.
unicode
or
nchar
-- we ignore tables
218
if
punicode
and
nunicode
and
categories
[
punicode
]
=
=
"
nd
"
and
categories
[
nunicode
]
=
=
"
nd
"
then
219
return
true
220
else
221
return
false
222
end
223
end
224
end
225 226
while
current
do
227
local
char
,
id
=
isglyph
(
current
)
228
if
char
then
229
local
font
=
id
--- nicer
230
local
data
=
fontcharacters
[
font
]
[
char
]
231
local
unicode
=
data
and
data
.
unicode
or
char
-- ignore tables
232
if
not
unicode
then
-- type(unicode) ~= "number"
233
-- no unicode so forget about it
234
elseif
unicode
=
=
separator
then
235
c
=
current
236
if
trace_split
then
237
setcolor
(
current
,
"
darkred
"
)
238
end
239
dataset
.
hasseparator
=
true
240
elseif
categories
[
unicode
]
=
=
"
nd
"
or
validseparators
[
unicode
]
then
241
if
c
then
242
if
not
a_start
then
243
a_start
=
current
244
end
245
a_stop
=
current
246
if
trace_split
then
247
setcolor
(
current
,
validseparators
[
unicode
]
and
"
darkcyan
"
or
"
darkblue
"
)
248
end
249
else
250
if
not
b_start
then
251
if
sign
then
252
b_start
=
sign
253
local
c
,
f
=
isglyph
(
sign
)
254
local
new
=
validsigns
[
c
]
255
if
char
=
=
new
or
not
fontcharacters
[
f
]
[
new
]
then
256
if
trace_split
then
257
setcolor
(
sign
,
"
darkyellow
"
)
258
end
259
else
260
setchar
(
sign
,
new
)
261
if
trace_split
then
262
setcolor
(
sign
,
"
darkmagenta
"
)
263
end
264
end
265
sign
=
nil
266
b_stop
=
current
267
else
268
b_start
=
current
269
b_stop
=
current
270
end
271
else
272
b_stop
=
current
273
end
274
if
trace_split
and
current
~
=
sign
then
275
setcolor
(
current
,
validseparators
[
unicode
]
and
"
darkcyan
"
or
"
darkblue
"
)
276
end
277
end
278
elseif
not
b_start
then
279
sign
=
validsigns
[
unicode
]
and
current
280
-- if trace_split then
281
-- setcolor(current,"darkgreen")
282
-- end
283
end
284
elseif
(
b_start
or
a_start
)
and
id
=
=
glue_code
then
285
-- maybe only in number mode
286
-- somewhat inefficient
287
if
bothdigit
(
current
)
then
288
local
width
=
fontcharacters
[
getfont
(
b_start
or
a_start
)
]
[
separator
or
period
]
.
width
289
setglue
(
current
,
width
,
0
,
0
)
290
setattr
(
current
,
a_character
,
punctuationspace
)
291
if
a_start
then
292
a_stop
=
current
293
elseif
b_start
then
294
b_stop
=
current
295
end
296
end
297
end
298
current
=
getnext
(
current
)
299
end
300
else
301
while
current
do
302
local
char
,
id
=
isglyph
(
current
)
303
if
char
then
304
local
font
=
id
-- nicer
305
-- local unicode = unicodes[font][char]
306
local
unicode
=
fontcharacters
[
font
]
[
char
]
.
unicode
or
char
-- ignore tables
307
if
not
unicode
then
308
-- no unicode so forget about it
309
elseif
unicode
=
=
separator
then
310
c
=
current
311
if
trace_split
then
312
setcolor
(
current
,
"
darkred
"
)
313
end
314
dataset
.
hasseparator
=
true
315
else
316
if
c
then
317
if
not
a_start
then
318
a_start
=
current
319
end
320
a_stop
=
current
321
if
trace_split
then
322
setcolor
(
current
,
"
darkgreen
"
)
323
end
324
else
325
if
not
b_start
then
326
b_start
=
current
327
end
328
b_stop
=
current
329
if
trace_split
then
330
setcolor
(
current
,
"
darkblue
"
)
331
end
332
end
333
end
334
end
335
current
=
getnext
(
current
)
336
end
337
end
338
local
predefined
=
dataset
.
predefined
339
local
before
,
after
340
if
predefined
then
341
before
=
b_start
and
getdimensions
(
b_start
,
getnext
(
b_stop
)
)
or
0
342
after
=
a_start
and
getdimensions
(
a_start
,
getnext
(
a_stop
)
)
or
0
343
else
344
local
entry
=
list
[
row
]
345
if
entry
then
346
before
=
entry
.
before
or
0
347
after
=
entry
.
after
or
0
348
else
349
before
=
b_start
and
getdimensions
(
b_start
,
getnext
(
b_stop
)
)
or
0
350
after
=
a_start
and
getdimensions
(
a_start
,
getnext
(
a_stop
)
)
or
0
351
list
[
row
]
=
{
352
before
=
before
,
353
after
=
after
,
354
}
355
return
head
,
true
356
end
357
if
not
dataset
.
collected
then
358
-- print("[maxbefore] [maxafter]")
359
local
maxbefore
=
0
360
local
maxafter
=
0
361
for
k
,
v
in
next
,
list
do
362
local
before
=
v
.
before
363
local
after
=
v
.
after
364
if
before
and
before
>
maxbefore
then
365
maxbefore
=
before
366
end
367
if
after
and
after
>
maxafter
then
368
maxafter
=
after
369
end
370
end
371
dataset
.
maxbefore
=
maxbefore
372
dataset
.
maxafter
=
maxafter
373
dataset
.
collected
=
true
374
end
375
end
376
local
maxbefore
=
dataset
.
maxbefore
377
local
maxafter
=
dataset
.
maxafter
378
local
new_kern
=
trace_split
and
traced_kern
or
new_kern
379
if
b_start
then
380
if
before
<
maxbefore
then
381
head
=
insert_node_before
(
head
,
b_start
,
new_kern
(
maxbefore
-
before
)
)
382
end
383
if
not
c
then
384
-- print("[before]")
385
if
dataset
.
hasseparator
then
386
local
width
=
fontcharacters
[
getfont
(
b_start
)
]
[
separator
]
.
width
387
insert_node_after
(
head
,
b_stop
,
new_kern
(
maxafter
+
width
)
)
388
end
389
elseif
a_start
then
390
-- print("[before] [separator] [after]")
391
if
after
<
maxafter
then
392
insert_node_after
(
head
,
a_stop
,
new_kern
(
maxafter
-
after
)
)
393
end
394
else
395
-- print("[before] [separator]")
396
if
maxafter
>
0
then
397
insert_node_after
(
head
,
c
,
new_kern
(
maxafter
)
)
398
end
399
end
400
elseif
a_start
then
401
if
c
then
402
-- print("[separator] [after]")
403
if
maxbefore
>
0
then
404
head
=
insert_node_before
(
head
,
c
,
new_kern
(
maxbefore
)
)
405
end
406
else
407
-- print("[after]")
408
local
width
=
fontcharacters
[
getfont
(
b_stop
)
]
[
separator
]
.
width
409
head
=
insert_node_before
(
head
,
a_start
,
new_kern
(
maxbefore
+
width
)
)
410
end
411
if
after
<
maxafter
then
412
insert_node_after
(
head
,
a_stop
,
new_kern
(
maxafter
-
after
)
)
413
end
414
elseif
c
then
415
-- print("[separator]")
416
if
maxbefore
>
0
then
417
head
=
insert_node_before
(
head
,
c
,
new_kern
(
maxbefore
)
)
418
end
419
if
maxafter
>
0
then
420
insert_node_after
(
head
,
c
,
new_kern
(
maxafter
)
)
421
end
422
end
423
return
head
424
end
425