typo-dua.lua /size: 29 Kb    last modification: 2020-07-01 14:35
1
if
not
modules
then
modules
=
{
}
end
modules
[
'
typo-dua
'
]
=
{
2
version
=
1
.
001
,
3
comment
=
"
companion to typo-dir.mkiv
"
,
4
author
=
"
Hans Hagen, PRAGMA-ADE, Hasselt NL
"
,
5
copyright
=
"
PRAGMA ADE / ConTeXt Development Team / See below
"
,
6
license
=
"
see context related readme files / whatever applies
"
,
7
comment
=
"
Unicode bidi (sort of) variant a
"
,
8
derived
=
"
derived from t-bidi by Khaled Hosny who derived from minibidi.c by Arabeyes
"
,
9
}
10 11
-- Comment by Khaled Hosny:
12
--
13
-- This code started as a line for line translation of Arabeyes' minibidi.c from C to Lua,
14
-- excluding parts that of no use to us like shaping. The C code is Copyright (c) 2004
15
-- Ahmad Khalifa, and is distributed under the MIT Licence. The full license text can be
16
-- found at: http://svn.arabeyes.org/viewvc/projects/adawat/minibidi/LICENCE.
17
--
18
-- Comment by Hans Hagen:
19
--
20
-- The initial conversion to Lua has been done by Khaled Hosny. As a first step I optimized the
21
-- code (to suit todays context mkiv). Next I fixed the foreign object handling, for instance,
22
-- we can skip over math but we need to inject before the open math node and after the close node,
23
-- so we need to keep track of the endpoint. After I fixed that bit I realized that it was possible
24
-- to generalize the object skipper if only because it saves memory (and processing time). The
25
-- current implementation is about three times as fast (roughly measured) and I can probably squeeze
26
-- out some more, only to sacrifice soem when I start adding features. A next stage will be to have
27
-- more granularity in foreign objects. Of course all errors are mine. I'll also added the usual bit
28
-- of context tracing and reshuffled some code. A memory optimization is on the agenda (already sort
29
-- of prepared). It is no longer line by line.
30
--
31
-- The first implementation of bidi in context started out from examples of mixed usage (including
32
-- more than text) with an at that point bugged r2l support. It has some alternatives for letting
33
-- the tex markup having a bit higher priority. I will probably add some local (style driven)
34
-- overrides to the following code as well. It also means that we can selectively enable and disable
35
-- the parser (because a document wide appliance migh tnot be what we want). This will bring a
36
-- slow down but not that much. (I need to check with Idris why we have things like isol there.)
37
--
38
-- We'll probably keep multiple methods around (this is just a side track of improving the already
39
-- available scanner). I need to look into the changed unicode recomendations anyway as a first
40
-- impression is that some fuzzyness has been removed. I finally need to spend time on those specs. So,
41
-- there will be a third variant (written from scratch) so some point. The fun about TeX is that we
42
-- can provide alternative solutions (given that it doesn't bloat the engine!)
43
--
44
-- A test with some hebrew, mixed with hboxes with latin/hebrew and simple math. In fact this triggered
45
-- playing with bidi again:
46
--
47
-- 0.11 : nothing
48
-- 0.14 : 0.03 node list only, one pass
49
-- 0.23 : 0.12 close to unicode bidi, multipass
50
-- 0.44 : 0.33 original previous
51
--
52
-- todo: check for introduced errors
53
-- todo: reuse list, we have size, so we can just change values (and auto allocate when not there)
54
-- todo: reuse the stack
55
-- todo: no need for a max check
56
-- todo: collapse bound similar ranges (not ok yet)
57
-- tood: combine some sweeps
58
--
59
-- This one wil get frozen (or if needed in sync with basic t-bidi) and I will explore more options
60
-- in typo-dub.lua. There I might also be able to improve performance a bit. Derived and improved
61
-- versions will also be sped up
62 63
local
insert
,
remove
,
unpack
,
concat
=
table
.
insert
,
table
.
remove
,
table
.
unpack
,
table
.
concat
64
local
utfchar
=
utf
.
char
65
local
formatters
=
string
.
formatters
66 67
local
directiondata
=
characters
.
directions
68
local
mirrordata
=
characters
.
mirrors
69 70
local
nuts
=
nodes
.
nuts
71 72
local
getnext
=
nuts
.
getnext
73
local
getid
=
nuts
.
getid
74
local
getsubtype
=
nuts
.
getsubtype
75
local
getlist
=
nuts
.
getlist
76
local
getchar
=
nuts
.
getchar
77
local
getprop
=
nuts
.
getprop
78
local
getdirection
=
nuts
.
getdirection
79 80
local
setprop
=
nuts
.
setprop
81
local
setchar
=
nuts
.
setchar
82
local
setdirection
=
nuts
.
setdirection
83
----- setattrlist = nuts.setattrlist
84 85
local
remove_node
=
nuts
.
remove
86
local
insert_node_after
=
nuts
.
insert_after
87
local
insert_node_before
=
nuts
.
insert_before
88
local
start_of_par
=
nuts
.
start_of_par
89 90
local
nodepool
=
nuts
.
pool
91
local
new_direction
=
nodepool
.
direction
92 93
local
nodecodes
=
nodes
.
nodecodes
94
local
gluecodes
=
nodes
.
gluecodes
95 96
local
glyph_code
=
nodecodes
.
glyph
97
local
glue_code
=
nodecodes
.
glue
98
local
hlist_code
=
nodecodes
.
hlist
99
local
vlist_code
=
nodecodes
.
vlist
100
local
math_code
=
nodecodes
.
math
101
local
dir_code
=
nodecodes
.
dir
102
local
localpar_code
=
nodecodes
.
localpar
103 104
local
parfillskip_code
=
gluecodes
.
parfillskip
105 106
local
dirvalues
=
nodes
.
dirvalues
107
local
lefttoright_code
=
dirvalues
.
lefttoright
108
local
righttoleft_code
=
dirvalues
.
righttoleft
109 110
local
maximum_stack
=
60
111 112
local
directions
=
typesetters
.
directions
113
local
setcolor
=
directions
.
setcolor
114 115
local
remove_controls
=
true
directives
.
register
(
"
typesetters.directions.one.removecontrols
"
,
function
(
v
)
remove_controls
=
v
end
)
116 117
local
report_directions
=
logs
.
reporter
(
"
typesetting
"
,
"
directions one
"
)
118 119
local
trace_directions
=
false
trackers
.
register
(
"
typesetters.directions
"
,
function
(
v
)
trace_directions
=
v
end
)
120
local
trace_details
=
false
trackers
.
register
(
"
typesetters.directions.details
"
,
function
(
v
)
trace_details
=
v
end
)
121 122 123 124 125
local
whitespace
=
{
126
lre
=
true
,
127
rle
=
true
,
128
lro
=
true
,
129
rlo
=
true
,
130
pdf
=
true
,
131
bn
=
true
,
132
ws
=
true
,
133
}
134 135
local
b_s_ws_on
=
{
136
b
=
true
,
137
s
=
true
,
138
ws
=
true
,
139
on
=
true
140
}
141 142
-- tracing
143 144
local
function
show_list
(
list
,
size
,
what
)
145
local
what
=
what
or
"
direction
"
146
local
joiner
=
utfchar
(
0x200C
)
147
local
result
=
{
}
148
for
i
=
1
,
size
do
149
local
entry
=
list
[
i
]
150
local
character
=
entry
.
char
151
local
direction
=
entry
[
what
]
152
if
character
=
=
0xFFFC
then
153
local
first
=
entry
.
id
154
local
last
=
entry
.
last
155
local
skip
=
entry
.
skip
156
if
last
then
157
result
[
i
]
=
formatters
[
"
%-3s:%s %s..%s (%i)
"
]
(
direction
,
joiner
,
nodecodes
[
first
]
,
nodecodes
[
last
]
,
skip
or
0
)
158
else
159
result
[
i
]
=
formatters
[
"
%-3s:%s %s (%i)
"
]
(
direction
,
joiner
,
nodecodes
[
first
]
,
skip
or
0
)
160
end
161
elseif
character
>
=
0x202A
and
character
<
=
0x202C
then
162
result
[
i
]
=
formatters
[
"
%-3s:%s %U
"
]
(
direction
,
joiner
,
character
)
163
else
164
result
[
i
]
=
formatters
[
"
%-3s:%s %c %U
"
]
(
direction
,
joiner
,
character
,
character
)
165
end
166
end
167
return
concat
(
result
,
joiner
.
.
"
|
"
.
.
joiner
)
168
end
169 170
-- preparation
171 172
local
function
show_done
(
list
,
size
)
173
local
joiner
=
utfchar
(
0x200C
)
174
local
result
=
{
}
175
for
i
=
1
,
size
do
176
local
entry
=
list
[
i
]
177
local
character
=
entry
.
char
178
local
begindir
=
entry
.
begindir
179
local
enddir
=
entry
.
enddir
180
if
begindir
then
181
result
[
#
result
+
1
]
=
formatters
[
"
<%s>
"
]
(
begindir
)
182
end
183
if
entry
.
remove
then
184
-- continue
185
elseif
character
=
=
0xFFFC
then
186
result
[
#
result
+
1
]
=
formatters
[
"
<%s>
"
]
(
"
?
"
)
187
elseif
character
=
=
0x0020
then
188
result
[
#
result
+
1
]
=
formatters
[
"
<%s>
"
]
(
"
"
)
189
elseif
character
>
=
0x202A
and
character
<
=
0x202C
then
190
result
[
#
result
+
1
]
=
formatters
[
"
<%s>
"
]
(
entry
.
original
)
191
else
192
result
[
#
result
+
1
]
=
utfchar
(
character
)
193
end
194
if
enddir
then
195
result
[
#
result
+
1
]
=
formatters
[
"
<%s>
"
]
(
enddir
)
196
end
197
end
198
return
concat
(
result
,
joiner
)
199
end
200 201
-- keeping the list and overwriting doesn't save much runtime, only a few percent
202
-- char is only used for mirror, so in fact we can as well only store it for
203
-- glyphs only
204 205
local
function
build_list
(
head
)
-- todo: store node pointer ... saves loop
206
-- P1
207
local
current
=
head
208
local
list
=
{
}
209
local
size
=
0
210
while
current
do
211
size
=
size
+
1
212
local
id
=
getid
(
current
)
213
if
getprop
(
current
,
"
directions
"
)
then
214
local
skip
=
0
215
local
last
=
id
216
current
=
getnext
(
current
)
217
while
current
do
218
local
id
=
getid
(
current
)
219
if
getprop
(
current
,
"
directions
"
)
then
220
skip
=
skip
+
1
221
last
=
id
222
current
=
getnext
(
current
)
223
else
224
break
225
end
226
end
227
if
id
=
=
last
then
-- the start id
228
list
[
size
]
=
{
char
=
0xFFFC
,
direction
=
"
on
"
,
original
=
"
on
"
,
level
=
0
,
skip
=
skip
,
id
=
id
}
229
else
230
list
[
size
]
=
{
char
=
0xFFFC
,
direction
=
"
on
"
,
original
=
"
on
"
,
level
=
0
,
skip
=
skip
,
id
=
id
,
last
=
last
}
231
end
232
elseif
id
=
=
glyph_code
then
233
local
chr
=
getchar
(
current
)
234
local
dir
=
directiondata
[
chr
]
235
list
[
size
]
=
{
char
=
chr
,
direction
=
dir
,
original
=
dir
,
level
=
0
}
236
current
=
getnext
(
current
)
237
elseif
id
=
=
glue_code
then
-- and how about kern
238
list
[
size
]
=
{
char
=
0x0020
,
direction
=
"
ws
"
,
original
=
"
ws
"
,
level
=
0
}
239
current
=
getnext
(
current
)
240
elseif
id
=
=
dir_code
then
241
local
direction
,
pop
=
getdirection
(
current
)
242
if
direction
=
=
lefttoright_code
then
243
if
pop
then
244
list
[
size
]
=
{
char
=
0x202C
,
direction
=
"
pdf
"
,
original
=
"
pdf
"
,
level
=
0
}
245
else
246
list
[
size
]
=
{
char
=
0x202A
,
direction
=
"
lre
"
,
original
=
"
lre
"
,
level
=
0
}
247
end
248
elseif
direction
=
=
righttoleft_code
then
249
if
pop
then
250
list
[
size
]
=
{
char
=
0x202C
,
direction
=
"
pdf
"
,
original
=
"
pdf
"
,
level
=
0
}
251
else
252
list
[
size
]
=
{
char
=
0x202B
,
direction
=
"
rle
"
,
original
=
"
rle
"
,
level
=
0
}
253
end
254
else
255
list
[
size
]
=
{
char
=
0xFFFC
,
direction
=
"
on
"
,
original
=
"
on
"
,
level
=
0
,
id
=
id
}
-- object replacement character
256
end
257
current
=
getnext
(
current
)
258
elseif
id
=
=
math_code
then
259
local
skip
=
0
260
current
=
getnext
(
current
)
261
while
getid
(
current
)
~
=
math_code
do
262
skip
=
skip
+
1
263
current
=
getnext
(
current
)
264
end
265
skip
=
skip
+
1
266
current
=
getnext
(
current
)
267
list
[
size
]
=
{
char
=
0xFFFC
,
direction
=
"
on
"
,
original
=
"
on
"
,
level
=
0
,
skip
=
skip
,
id
=
id
}
268
else
269
local
skip
=
0
270
local
last
=
id
271
current
=
getnext
(
current
)
272
while
n
do
273
local
id
=
getid
(
current
)
274
if
id
~
=
glyph_code
and
id
~
=
glue_code
and
id
~
=
dir_code
then
275
skip
=
skip
+
1
276
last
=
id
277
current
=
getnext
(
current
)
278
else
279
break
280
end
281
end
282
if
id
=
=
last
then
-- the start id
283
list
[
size
]
=
{
char
=
0xFFFC
,
direction
=
"
on
"
,
original
=
"
on
"
,
level
=
0
,
skip
=
skip
,
id
=
id
}
284
else
285
list
[
size
]
=
{
char
=
0xFFFC
,
direction
=
"
on
"
,
original
=
"
on
"
,
level
=
0
,
skip
=
skip
,
id
=
id
,
last
=
last
}
286
end
287
end
288
end
289
return
list
,
size
290
end
291 292
-- the action
293 294
-- local function find_run_limit_et(list,run_start,limit)
295
-- local run_limit = run_start
296
-- local i = run_start
297
-- while i <= limit and list[i].direction == "et" do
298
-- run_limit = i
299
-- i = i + 1
300
-- end
301
-- return run_limit
302
-- end
303 304
local
function
find_run_limit_et
(
list
,
start
,
limit
)
-- returns last match
305
for
i
=
start
,
limit
do
306
if
list
[
i
]
.
direction
=
=
"
et
"
then
307
start
=
i
308
else
309
return
start
310
end
311
end
312
return
start
313
end
314 315
-- local function find_run_limit_b_s_ws_on(list,run_start,limit)
316
-- local run_limit = run_start
317
-- local i = run_start
318
-- while i <= limit and b_s_ws_on[list[i].direction] do
319
-- run_limit = i
320
-- i = i + 1
321
-- end
322
-- return run_limit
323
-- end
324 325
local
function
find_run_limit_b_s_ws_on
(
list
,
start
,
limit
)
326
for
i
=
start
,
limit
do
327
if
b_s_ws_on
[
list
[
i
]
.
direction
]
then
328
start
=
i
329
else
330
return
start
331
end
332
end
333
return
start
334
end
335 336
local
function
get_baselevel
(
head
,
list
,
size
,
direction
)
337
-- This is an adapted version:
338
if
direction
=
=
lefttoright_code
or
direction
=
=
righttoleft_code
then
339
return
direction
,
true
340
elseif
getid
(
head
)
=
=
localpar_code
and
start_of_par
(
head
)
then
341
direction
=
getdirection
(
head
)
342
if
direction
=
=
lefttoright_code
or
direction
=
=
righttoleft_code
then
343
return
direction
,
true
344
end
345
end
346
-- for old times sake we we handle strings too
347
if
direction
=
=
"
TLT
"
then
348
return
lefttoright_code
,
true
349
elseif
direction
=
=
"
TRT
"
then
350
return
righttoleft_code
,
true
351
end
352
-- P2, P3
353
for
i
=
1
,
size
do
354
local
entry
=
list
[
i
]
355
local
direction
=
entry
.
direction
356
if
direction
=
=
"
r
"
or
direction
=
=
"
al
"
then
357
return
righttoleft_code
,
true
358
elseif
direction
=
=
"
l
"
then
359
return
lefttoright_code
,
true
360
end
361
end
362
return
lefttoright_code
,
false
363
end
364 365
local
function
resolve_explicit
(
list
,
size
,
baselevel
)
366
-- X1
367
local
level
=
baselevel
368
local
override
=
"
on
"
369
local
stack
=
{
}
370
local
nofstack
=
0
371
for
i
=
1
,
size
do
372
local
entry
=
list
[
i
]
373
local
direction
=
entry
.
direction
374
-- X2
375
if
direction
=
=
"
rle
"
then
376
if
nofstack
<
maximum_stack
then
377
nofstack
=
nofstack
+
1
378
stack
[
nofstack
]
=
{
level
,
override
}
379
level
=
level
+
(
level
%
2
=
=
1
and
2
or
1
)
-- least_greater_odd(level)
380
override
=
"
on
"
381
entry
.
level
=
level
382
entry
.
direction
=
"
bn
"
383
entry
.
remove
=
true
384
elseif
trace_directions
then
385
report_directions
(
"
stack overflow at position %a with direction %a
"
,
i
,
direction
)
386
end
387
-- X3
388
elseif
direction
=
=
"
lre
"
then
389
if
nofstack
<
maximum_stack
then
390
nofstack
=
nofstack
+
1
391
stack
[
nofstack
]
=
{
level
,
override
}
392
level
=
level
+
(
level
%
2
=
=
1
and
1
or
2
)
-- least_greater_even(level)
393
override
=
"
on
"
394
entry
.
level
=
level
395
entry
.
direction
=
"
bn
"
396
entry
.
remove
=
true
397
elseif
trace_directions
then
398
report_directions
(
"
stack overflow at position %a with direction %a
"
,
i
,
direction
)
399
end
400
-- X4
401
elseif
direction
=
=
"
rlo
"
then
402
if
nofstack
<
maximum_stack
then
403
nofstack
=
nofstack
+
1
404
stack
[
nofstack
]
=
{
level
,
override
}
405
level
=
level
+
(
level
%
2
=
=
1
and
2
or
1
)
-- least_greater_odd(level)
406
override
=
"
r
"
407
entry
.
level
=
level
408
entry
.
direction
=
"
bn
"
409
entry
.
remove
=
true
410
elseif
trace_directions
then
411
report_directions
(
"
stack overflow at position %a with direction %a
"
,
i
,
direction
)
412
end
413
-- X5
414
elseif
direction
=
=
"
lro
"
then
415
if
nofstack
<
maximum_stack
then
416
nofstack
=
nofstack
+
1
417
stack
[
nofstack
]
=
{
level
,
override
}
418
level
=
level
+
(
level
%
2
=
=
1
and
1
or
2
)
-- least_greater_even(level)
419
override
=
"
l
"
420
entry
.
level
=
level
421
entry
.
direction
=
"
bn
"
422
entry
.
remove
=
true
423
elseif
trace_directions
then
424
report_directions
(
"
stack overflow at position %a with direction %a
"
,
i
,
direction
)
425
end
426
-- X7
427
elseif
direction
=
=
"
pdf
"
then
428
if
noifstack
>
0
then
429
local
stacktop
=
stack
[
nofstack
]
430
nofstack
=
nofstack
-
1
431
level
=
stacktop
[
1
]
432
override
=
stacktop
[
2
]
433
entry
.
level
=
level
434
entry
.
direction
=
"
bn
"
435
entry
.
remove
=
true
436
elseif
trace_directions
then
437
report_directions
(
"
stack underflow at position %a with direction %a
"
,
i
,
direction
)
438
end
439
-- X6
440
else
441
entry
.
level
=
level
442
if
override
~
=
"
on
"
then
443
entry
.
direction
=
override
444
end
445
end
446
end
447
-- X8 (reset states and overrides after paragraph)
448
end
449 450
local
function
resolve_weak
(
list
,
size
,
start
,
limit
,
sor
,
eor
)
451
-- W1
452
for
i
=
start
,
limit
do
453
local
entry
=
list
[
i
]
454
if
entry
.
direction
=
=
"
nsm
"
then
455
if
i
=
=
start
then
456
entry
.
direction
=
sor
457
else
458
entry
.
direction
=
list
[
i
-1
]
.
direction
459
end
460
end
461
end
462
-- W2
463
for
i
=
start
,
limit
do
464
local
entry
=
list
[
i
]
465
if
entry
.
direction
=
=
"
en
"
then
466
for
j
=
i
-1
,
start
,
-1
do
467
local
prev
=
list
[
j
]
468
local
direction
=
prev
.
direction
469
if
direction
=
=
"
al
"
then
470
entry
.
direction
=
"
an
"
471
break
472
elseif
direction
=
=
"
r
"
or
direction
=
=
"
l
"
then
473
break
474
end
475
end
476
end
477
end
478
-- W3
479
for
i
=
start
,
limit
do
480
local
entry
=
list
[
i
]
481
if
entry
.
direction
=
=
"
al
"
then
482
entry
.
direction
=
"
r
"
483
end
484
end
485
-- W4
486
for
i
=
start
+
1
,
limit
-1
do
487
local
entry
=
list
[
i
]
488
local
direction
=
entry
.
direction
489
if
direction
=
=
"
es
"
then
490
if
list
[
i
-1
]
.
direction
=
=
"
en
"
and
list
[
i
+
1
]
.
direction
=
=
"
en
"
then
491
entry
.
direction
=
"
en
"
492
end
493
elseif
direction
=
=
"
cs
"
then
494
local
prevdirection
=
list
[
i
-1
]
.
direction
495
if
prevdirection
=
=
"
en
"
then
496
if
list
[
i
+
1
]
.
direction
=
=
"
en
"
then
497
entry
.
direction
=
"
en
"
498
end
499
elseif
prevdirection
=
=
"
an
"
and
list
[
i
+
1
]
.
direction
=
=
"
an
"
then
500
entry
.
direction
=
"
an
"
501
end
502
end
503
end
504
-- W5
505
local
i
=
start
506
while
i
<
=
limit
do
507
if
list
[
i
]
.
direction
=
=
"
et
"
then
508
local
runstart
=
i
509
local
runlimit
=
find_run_limit_et
(
list
,
runstart
,
limit
)
-- when moved inline we can probably collapse a lot
510
local
rundirection
=
runstart
=
=
start
and
sor
or
list
[
runstart
-1
]
.
direction
511
if
rundirection
~
=
"
en
"
then
512
rundirection
=
runlimit
=
=
limit
and
eor
or
list
[
runlimit
+
1
]
.
direction
513
end
514
if
rundirection
=
=
"
en
"
then
515
for
j
=
runstart
,
runlimit
do
516
list
[
j
]
.
direction
=
"
en
"
517
end
518
end
519
i
=
runlimit
520
end
521
i
=
i
+
1
522
end
523
-- W6
524
for
i
=
start
,
limit
do
525
local
entry
=
list
[
i
]
526
local
direction
=
entry
.
direction
527
if
direction
=
=
"
es
"
or
direction
=
=
"
et
"
or
direction
=
=
"
cs
"
then
528
entry
.
direction
=
"
on
"
529
end
530
end
531
-- W7
532
for
i
=
start
,
limit
do
533
local
entry
=
list
[
i
]
534
if
entry
.
direction
=
=
"
en
"
then
535
local
prev_strong
=
sor
536
for
j
=
i
-1
,
start
,
-1
do
537
local
direction
=
list
[
j
]
.
direction
538
if
direction
=
=
"
l
"
or
direction
=
=
"
r
"
then
539
prev_strong
=
direction
540
break
541
end
542
end
543
if
prev_strong
=
=
"
l
"
then
544
entry
.
direction
=
"
l
"
545
end
546
end
547
end
548
end
549 550
local
function
resolve_neutral
(
list
,
size
,
start
,
limit
,
sor
,
eor
)
551
-- N1, N2
552
for
i
=
start
,
limit
do
553
local
entry
=
list
[
i
]
554
if
b_s_ws_on
[
entry
.
direction
]
then
555
local
leading_direction
,
trailing_direction
,
resolved_direction
556
local
runstart
=
i
557
local
runlimit
=
find_run_limit_b_s_ws_on
(
list
,
runstart
,
limit
)
558
if
runstart
=
=
start
then
559
leading_direction
=
sor
560
else
561
leading_direction
=
list
[
runstart
-1
]
.
direction
562
if
leading_direction
=
=
"
en
"
or
leading_direction
=
=
"
an
"
then
563
leading_direction
=
"
r
"
564
end
565
end
566
if
runlimit
=
=
limit
then
567
trailing_direction
=
eor
568
else
569
trailing_direction
=
list
[
runlimit
+
1
]
.
direction
570
if
trailing_direction
=
=
"
en
"
or
trailing_direction
=
=
"
an
"
then
571
trailing_direction
=
"
r
"
572
end
573
end
574
if
leading_direction
=
=
trailing_direction
then
575
-- N1
576
resolved_direction
=
leading_direction
577
else
578
-- N2 / does the weird period
579
resolved_direction
=
entry
.
level
%
2
=
=
1
and
"
r
"
or
"
l
"
-- direction_of_level(entry.level)
580
end
581
for
j
=
runstart
,
runlimit
do
582
list
[
j
]
.
direction
=
resolved_direction
583
end
584
i
=
runlimit
585
end
586
i
=
i
+
1
587
end
588
end
589 590
-- local function resolve_implicit(list,size,start,limit,sor,eor)
591
-- -- I1
592
-- for i=start,limit do
593
-- local entry = list[i]
594
-- local level = entry.level
595
-- if level % 2 ~= 1 then -- not odd(level)
596
-- local direction = entry.direction
597
-- if direction == "r" then
598
-- entry.level = level + 1
599
-- elseif direction == "an" or direction == "en" then
600
-- entry.level = level + 2
601
-- end
602
-- end
603
-- end
604
-- -- I2
605
-- for i=start,limit do
606
-- local entry = list[i]
607
-- local level = entry.level
608
-- if level % 2 == 1 then -- odd(level)
609
-- local direction = entry.direction
610
-- if direction == "l" or direction == "en" or direction == "an" then
611
-- entry.level = level + 1
612
-- end
613
-- end
614
-- end
615
-- end
616 617
local
function
resolve_implicit
(
list
,
size
,
start
,
limit
,
sor
,
eor
)
618
for
i
=
start
,
limit
do
619
local
entry
=
list
[
i
]
620
local
level
=
entry
.
level
621
local
direction
=
entry
.
direction
622
if
level
%
2
~
=
1
then
-- even
623
-- I1
624
if
direction
=
=
"
r
"
then
625
entry
.
level
=
level
+
1
626
elseif
direction
=
=
"
an
"
or
direction
=
=
"
en
"
then
627
entry
.
level
=
level
+
2
628
end
629
else
630
-- I2
631
if
direction
=
=
"
l
"
or
direction
=
=
"
en
"
or
direction
=
=
"
an
"
then
632
entry
.
level
=
level
+
1
633
end
634
end
635
end
636
end
637 638
local
function
resolve_levels
(
list
,
size
,
baselevel
)
639
-- X10
640
local
start
=
1
641
while
start
<
size
do
642
local
level
=
list
[
start
]
.
level
643
local
limit
=
start
+
1
644
while
limit
<
size
and
list
[
limit
]
.
level
=
=
level
do
645
limit
=
limit
+
1
646
end
647
local
prev_level
=
start
=
=
1
and
baselevel
or
list
[
start
-1
]
.
level
648
local
next_level
=
limit
=
=
size
and
baselevel
or
list
[
limit
+
1
]
.
level
649
local
sor
=
(
level
>
prev_level
and
level
or
prev_level
)
%
2
=
=
1
and
"
r
"
or
"
l
"
-- direction_of_level(max(level,prev_level))
650
local
eor
=
(
level
>
next_level
and
level
or
next_level
)
%
2
=
=
1
and
"
r
"
or
"
l
"
-- direction_of_level(max(level,next_level))
651
-- W1 .. W7
652
resolve_weak
(
list
,
size
,
start
,
limit
,
sor
,
eor
)
653
-- N1 .. N2
654
resolve_neutral
(
list
,
size
,
start
,
limit
,
sor
,
eor
)
655
-- I1 .. I2
656
resolve_implicit
(
list
,
size
,
start
,
limit
,
sor
,
eor
)
657
start
=
limit
658
end
659
-- L1
660
for
i
=
1
,
size
do
661
local
entry
=
list
[
i
]
662
local
direction
=
entry
.
original
663
-- (1)
664
if
direction
=
=
"
s
"
or
direction
=
=
"
b
"
then
665
entry
.
level
=
baselevel
666
-- (2)
667
for
j
=
i
-1
,
1
,
-1
do
668
local
entry
=
list
[
j
]
669
if
whitespace
[
entry
.
original
]
then
670
entry
.
level
=
baselevel
671
else
672
break
673
end
674
end
675
end
676
end
677
-- (3)
678
for
i
=
size
,
1
,
-1
do
679
local
entry
=
list
[
i
]
680
if
whitespace
[
entry
.
original
]
then
681
entry
.
level
=
baselevel
682
else
683
break
684
end
685
end
686
-- L4
687
for
i
=
1
,
size
do
688
local
entry
=
list
[
i
]
689
if
entry
.
level
%
2
=
=
1
then
-- odd(entry.level)
690
local
mirror
=
mirrordata
[
entry
.
char
]
691
if
mirror
then
692
entry
.
mirror
=
mirror
693
end
694
end
695
end
696
end
697 698
local
function
insert_dir_points
(
list
,
size
)
699
-- L2, but no actual reversion is done, we simply annotate where
700
-- begindir/endddir node will be inserted.
701
local
maxlevel
=
0
702
local
finaldir
=
false
703
for
i
=
1
,
size
do
704
local
level
=
list
[
i
]
.
level
705
if
level
>
maxlevel
then
706
maxlevel
=
level
707
end
708
end
709
for
level
=
0
,
maxlevel
do
710
local
started
=
false
711
local
begindir
=
nil
712
local
enddir
=
nil
713
if
level
%
2
=
=
1
then
714
begindir
=
righttoleft_code
715
enddir
=
righttoleft_code
716
else
717
begindir
=
lefttoright_code
718
enddir
=
lefttoright_code
719
end
720
for
i
=
1
,
size
do
721
local
entry
=
list
[
i
]
722
if
entry
.
level
>
=
level
then
723
if
not
started
then
724
entry
.
begindir
=
begindir
725
started
=
true
726
end
727
else
728
if
started
then
729
list
[
i
-1
]
.
enddir
=
enddir
730
started
=
false
731
end
732
end
733
end
734
-- make sure to close the run at end of line
735
if
started
then
736
finaldir
=
enddir
737
end
738
end
739
if
finaldir
then
740
list
[
size
]
.
enddir
=
finaldir
741
end
742
end
743 744
local
function
apply_to_list
(
list
,
size
,
head
,
pardir
)
745
local
index
=
1
746
local
current
=
head
747
while
current
do
748
if
index
>
size
then
749
report_directions
(
"
fatal error, size mismatch
"
)
750
break
751
end
752
local
id
=
getid
(
current
)
753
local
entry
=
list
[
index
]
754
local
begindir
=
entry
.
begindir
755
local
enddir
=
entry
.
enddir
756
setprop
(
current
,
"
directions
"
,
true
)
757
if
id
=
=
glyph_code
then
758
local
mirror
=
entry
.
mirror
759
if
mirror
then
760
setchar
(
current
,
mirror
)
761
end
762
if
trace_directions
then
763
local
direction
=
entry
.
direction
764
setcolor
(
current
,
direction
,
false
,
mirror
)
765
end
766
elseif
id
=
=
hlist_code
or
id
=
=
vlist_code
then
767
setdirection
(
current
,
pardir
)
-- is this really needed?
768
elseif
id
=
=
glue_code
then
769
if
enddir
and
getsubtype
(
current
)
=
=
parfillskip_code
then
770
-- insert the last enddir before \parfillskip glue
771
local
d
=
new_direction
(
enddir
,
true
)
772
-- setprop(d,"directions",true)
773
-- setattrlist(d,current)
774
head
=
insert_node_before
(
head
,
current
,
d
)
775
enddir
=
false
776
end
777
elseif
begindir
then
778
if
id
=
=
localpar_code
and
start_of_par
(
current
)
then
779
-- localpar should always be the 1st node
780
local
d
=
new_direction
(
begindir
)
781
-- setprop(d,"directions",true)
782
-- setattrlist(d,current)
783
head
,
current
=
insert_node_after
(
head
,
current
,
d
)
784
begindir
=
nil
785
end
786
end
787
if
begindir
then
788
local
d
=
new_direction
(
begindir
)
789
-- setprop(d,"directions",true)
790
-- setattrlist(d,current)
791
head
=
insert_node_before
(
head
,
current
,
d
)
792
end
793
local
skip
=
entry
.
skip
794
if
skip
and
skip
>
0
then
795
for
i
=
1
,
skip
do
796
current
=
getnext
(
current
)
797
setprop
(
current
,
"
directions
"
,
true
)
798
end
799
end
800
if
enddir
then
801
local
d
=
new_direction
(
enddir
,
true
)
802
-- setprop(d,"directions",true)
803
-- setattrlist(d,current)
804
head
,
current
=
insert_node_after
(
head
,
current
,
d
)
805
end
806
if
not
entry
.
remove
then
807
current
=
getnext
(
current
)
808
elseif
remove_controls
then
809
-- X9
810
head
,
current
=
remove_node
(
head
,
current
,
true
)
811
else
812
current
=
getnext
(
current
)
813
end
814
index
=
index
+
1
815
end
816
return
head
817
end
818 819
local
function
process
(
head
,
direction
,
only_one
,
where
)
820
-- This is an adapted version:
821
local
list
,
size
=
build_list
(
head
)
822
local
baselevel
,
dirfound
=
get_baselevel
(
head
,
list
,
size
,
direction
)
823
if
not
dirfound
and
trace_details
then
824
report_directions
(
"
no initial direction found, gambling
"
)
825
end
826
if
trace_details
then
827
report_directions
(
"
before : %s
"
,
show_list
(
list
,
size
,
"
original
"
)
)
828
end
829
resolve_explicit
(
list
,
size
,
baselevel
)
830
resolve_levels
(
list
,
size
,
baselevel
)
831
insert_dir_points
(
list
,
size
)
832
if
trace_details
then
833
report_directions
(
"
after : %s
"
,
show_list
(
list
,
size
,
"
direction
"
)
)
834
report_directions
(
"
result : %s
"
,
show_done
(
list
,
size
)
)
835
end
836
return
apply_to_list
(
list
,
size
,
head
,
baselevel
)
837
end
838 839
directions
.
installhandler
(
interfaces
.
variables
.
one
,
process
)
840