1if not modules then modules = { } end modules [ ' scite-ctx-bidi ' ] = {
2 version = 1 . 001 ,
3 comment = " companion to scite-ctx.lua " ,
4 author = " Hans Hagen, PRAGMA-ADE, Hasselt NL " ,
5 copyright = " PRAGMA ADE / ConTeXt Development Team " ,
6 license = " see context related readme files " ,
7 comment = " Unicode bidi (sort of) variant c " ,
8}
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29local setmetatable = setmetatable
30
31local data = require ( " context.lexers.data.scite-context-data-bidi " )
32
33local directiondata = data . directions
34local mirrordata = data . mirrors
35local textclassdata = data . textclasses
36
37
38
39local maximum_stack = 0xFF
40local analyze_fences = false
41
42local whitespace = {
43 lre = true ,
44 rle = true ,
45 lro = true ,
46 rlo = true ,
47 pdf = true ,
48 bn = true ,
49 ws = true ,
50}
51
52local b_s_ws_on = {
53 b = true ,
54 s = true ,
55 ws = true ,
56 on = true
57}
58
59local mt_space = { __index = { char = 0x0020 , direction = " ws " , original = " ws " , level = 0 } }
60
61
62
63
64
65local stack = { }
66
67setmetatable ( stack , { __index = function ( t , k ) local v = { } t [ k ] = v return v end } )
68
69local function build_list ( list )
70
71 local size = # list
72 for i = 1 , size do
73 local chr = list [ i ]
74 if chr = = " " then
75 list [ i ] = setmetatable ( { } , mt_space )
76 else
77 local dir = directiondata [ chr ] or " l "
78 list [ i ] = { char = chr , direction = dir , original = dir , level = 0 }
79 end
80 end
81 return list , size
82end
83
84local function resolve_fences ( list , size , start , limit )
85
86 local nofstack = 0
87 for i = start , limit do
88 local entry = list [ i ]
89 if entry . direction = = " on " then
90 local char = entry . char
91 local mirror = mirrordata [ char ]
92 if mirror then
93 local class = textclassdata [ char ]
94 entry . mirror = mirror
95 entry . class = class
96 if class = = " open " then
97 nofstack = nofstack + 1
98 local stacktop = stack [ nofstack ]
99 stacktop [ 1 ] = mirror
100 stacktop [ 2 ] = i
101 stacktop [ 3 ] = false
102 elseif nofstack = = 0 then
103
104 elseif class = = " close " then
105 while nofstack > 0 do
106 local stacktop = stack [ nofstack ]
107 if stacktop [ 1 ] = = char then
108 local open = stacktop [ 2 ]
109 local close = i
110 list [ open ] . paired = close
111 list [ close ] . paired = open
112 break
113 else
114
115 end
116 nofstack = nofstack - 1
117 end
118 end
119 end
120 end
121 end
122end
123
124local function get_baselevel ( list , size , direction )
125 if direction = = " TRT " then
126 return 1 , " TRT " , true
127 elseif direction = = " TLT " then
128 return 0 , " TLT " , true
129 end
130
131 for i = 1 , size do
132 local entry = list [ i ]
133 local direction = entry . direction
134 if direction = = " r " or direction = = " al " then
135 return 1 , " TRT " , true
136 elseif direction = = " l " then
137 return 0 , " TLT " , true
138 end
139 end
140 return 0 , " TLT " , false
141end
142
143local function resolve_explicit ( list , size , baselevel )
144
145
146 local level = baselevel
147 local override = " on "
148 local nofstack = 0
149 for i = 1 , size do
150 local entry = list [ i ]
151 local direction = entry . direction
152
153 if direction = = " rle " then
154 if nofstack < maximum_stack then
155 nofstack = nofstack + 1
156 local stacktop = stack [ nofstack ]
157 stacktop [ 1 ] = level
158 stacktop [ 2 ] = override
159 level = level + ( level % 2 = = 1 and 2 or 1 )
160 override = " on "
161 entry . level = level
162 entry . direction = " bn "
163 entry . remove = true
164 end
165
166 elseif direction = = " lre " then
167 if nofstack < maximum_stack then
168 nofstack = nofstack + 1
169 local stacktop = stack [ nofstack ]
170 stacktop [ 1 ] = level
171 stacktop [ 2 ] = override
172 level = level + ( level % 2 = = 1 and 1 or 2 )
173 override = " on "
174 entry . level = level
175 entry . direction = " bn "
176 entry . remove = true
177 end
178
179 elseif direction = = " rlo " then
180 if nofstack < maximum_stack then
181 nofstack = nofstack + 1
182 local stacktop = stack [ nofstack ]
183 stacktop [ 1 ] = level
184 stacktop [ 2 ] = override
185 level = level + ( level % 2 = = 1 and 2 or 1 )
186 override = " r "
187 entry . level = level
188 entry . direction = " bn "
189 entry . remove = true
190 end
191
192 elseif direction = = " lro " then
193 if nofstack < maximum_stack then
194 nofstack = nofstack + 1
195 local stacktop = stack [ nofstack ]
196 stacktop [ 1 ] = level
197 stacktop [ 2 ] = override
198 level = level + ( level % 2 = = 1 and 1 or 2 )
199 override = " l "
200 entry . level = level
201 entry . direction = " bn "
202 entry . remove = true
203 end
204
205 elseif direction = = " pdf " then
206 if nofstack < maximum_stack then
207 local stacktop = stack [ nofstack ]
208 level = stacktop [ 1 ]
209 override = stacktop [ 2 ]
210 nofstack = nofstack - 1
211 entry . level = level
212 entry . direction = " bn "
213 entry . remove = true
214 end
215
216 else
217 entry . level = level
218 if override ~ = " on " then
219 entry . direction = override
220 end
221 end
222 end
223
224
225
226
227
228
229end
230
231local function resolve_weak ( list , size , start , limit , orderbefore , orderafter )
232
233
234 for i = start , limit do
235 local entry = list [ i ]
236 if entry . direction = = " nsm " then
237 if i = = start then
238 entry . direction = orderbefore
239 else
240 entry . direction = list [ i -1 ] . direction
241 end
242 end
243 end
244
245
246
247 for i = start , limit do
248 local entry = list [ i ]
249 if entry . direction = = " en " then
250 for j = i -1 , start , -1 do
251 local prev = list [ j ]
252 local direction = prev . direction
253 if direction = = " al " then
254 entry . direction = " an "
255 break
256 elseif direction = = " r " or direction = = " l " then
257 break
258 end
259 end
260 end
261 end
262
263
264
265 for i = start , limit do
266 local entry = list [ i ]
267 if entry . direction = = " al " then
268 entry . direction = " r "
269 end
270 end
271
272
273
274
275
276 if false then
277 for i = start + 1 , limit -1 do
278 local entry = list [ i ]
279 local direction = entry . direction
280 if direction = = " es " then
281 if list [ i -1 ] . direction = = " en " and list [ i + 1 ] . direction = = " en " then
282 entry . direction = " en "
283 end
284 elseif direction = = " cs " then
285 local prevdirection = list [ i -1 ] . direction
286 if prevdirection = = " en " then
287 if list [ i + 1 ] . direction = = " en " then
288 entry . direction = " en "
289 end
290 elseif prevdirection = = " an " and list [ i + 1 ] . direction = = " an " then
291 entry . direction = " an "
292 end
293 end
294 end
295 else
296 local runner = start + 2
297 local before = list [ start ]
298 local entry = list [ start + 1 ]
299 local after = list [ runner ]
300 while after do
301 local direction = entry . direction
302 if direction = = " es " then
303 if before and before . direction = = " en " and after . direction = = " en " then
304 entry . direction = " en "
305 end
306 elseif direction = = " cs " then
307 local prevdirection = before and before . direction
308 if prevdirection = = " en " then
309 if after . direction = = " en " then
310 entry . direction = " en "
311 end
312 elseif prevdirection = = " an " and after . direction = = " an " then
313 entry . direction = " an "
314 end
315 end
316 before = current
317 current = after
318 after = list [ runner ]
319 runner = runner + 1
320 end
321 end
322
323
324
325 local i = start
326 while i < = limit do
327 if list [ i ] . direction = = " et " then
328 local runstart = i
329 local runlimit = runstart
330 for i = runstart , limit do
331 if list [ i ] . direction = = " et " then
332 runlimit = i
333 else
334 break
335 end
336 end
337 local rundirection = runstart = = start and sor or ( runstart > 1 and list [ runstart -1 ] . direction )
338 if rundirection ~ = " en " then
339 rundirection = runlimit = = limit and orderafter or list [ runlimit + 1 ] . direction
340 end
341 if rundirection = = " en " then
342 for j = runstart , runlimit do
343 list [ j ] . direction = " en "
344 end
345 end
346 i = runlimit
347 end
348 i = i + 1
349 end
350
351
352
353 for i = start , limit do
354 local entry = list [ i ]
355 local direction = entry . direction
356 if direction = = " es " or direction = = " et " or direction = = " cs " then
357 entry . direction = " on "
358 end
359 end
360
361
362 for i = start , limit do
363 local entry = list [ i ]
364 if entry . direction = = " en " then
365 local prev_strong = orderbefore
366 for j = i -1 , start , -1 do
367 local direction = list [ j ] . direction
368 if direction = = " l " or direction = = " r " then
369 prev_strong = direction
370 break
371 end
372 end
373 if prev_strong = = " l " then
374 entry . direction = " l "
375 end
376 end
377 end
378end
379
380local function resolve_neutral ( list , size , start , limit , orderbefore , orderafter )
381
382 for i = start , limit do
383 local entry = list [ i ]
384 if b_s_ws_on [ entry . direction ] then
385
386 local leading_direction , trailing_direction , resolved_direction
387 local runstart = i
388 local runlimit = runstart
389 for j = runstart + 1 , limit do
390 if b_s_ws_on [ list [ j ] . direction ] then
391 runlimit = j
392 else
393 break
394 end
395 end
396 if runstart = = start then
397 leading_direction = orderbefore
398 else
399 leading_direction = list [ runstart -1 ] . direction
400 if leading_direction = = " en " or leading_direction = = " an " then
401 leading_direction = " r "
402 end
403 end
404 if runlimit = = limit then
405 trailing_direction = orderafter
406 else
407 trailing_direction = list [ runlimit + 1 ] . direction
408 if trailing_direction = = " en " or trailing_direction = = " an " then
409 trailing_direction = " r "
410 end
411 end
412 if leading_direction = = trailing_direction then
413
414 resolved_direction = leading_direction
415 else
416
417 resolved_direction = entry . level % 2 = = 1 and " r " or " l "
418 end
419 for j = runstart , runlimit do
420 list [ j ] . direction = resolved_direction
421 end
422 i = runlimit
423 end
424 i = i + 1
425 end
426end
427
428local function resolve_implicit ( list , size , start , limit , orderbefore , orderafter , baselevel )
429 for i = start , limit do
430 local entry = list [ i ]
431 local level = entry . level
432 local direction = entry . direction
433 if level % 2 ~ = 1 then
434
435 if direction = = " r " then
436 entry . level = level + 1
437 elseif direction = = " an " or direction = = " en " then
438 entry . level = level + 2
439 end
440 else
441
442 if direction = = " l " or direction = = " en " or direction = = " an " then
443 entry . level = level + 1
444 end
445 end
446 end
447end
448
449local function resolve_levels ( list , size , baselevel , analyze_fences )
450
451 local start = 1
452 while start < size do
453 local level = list [ start ] . level
454 local limit = start + 1
455 while limit < size and list [ limit ] . level = = level do
456 limit = limit + 1
457 end
458 local prev_level = start = = 1 and baselevel or list [ start -1 ] . level
459 local next_level = limit = = size and baselevel or list [ limit + 1 ] . level
460 local orderbefore = ( level > prev_level and level or prev_level ) % 2 = = 1 and " r " or " l "
461 local orderafter = ( level > next_level and level or next_level ) % 2 = = 1 and " r " or " l "
462
463 resolve_weak ( list , size , start , limit , orderbefore , orderafter )
464
465 if analyze_fences then
466 resolve_fences ( list , size , start , limit )
467 end
468
469 resolve_neutral ( list , size , start , limit , orderbefore , orderafter )
470
471 resolve_implicit ( list , size , start , limit , orderbefore , orderafter , baselevel )
472 start = limit
473 end
474
475 for i = 1 , size do
476 local entry = list [ i ]
477 local direction = entry . original
478
479 if direction = = " s " or direction = = " b " then
480 entry . level = baselevel
481
482 for j = i -1 , 1 , -1 do
483 local entry = list [ j ]
484 if whitespace [ entry . original ] then
485 entry . level = baselevel
486 else
487 break
488 end
489 end
490 end
491 end
492
493 for i = size , 1 , -1 do
494 local entry = list [ i ]
495 if whitespace [ entry . original ] then
496 entry . level = baselevel
497 else
498 break
499 end
500 end
501
502 if analyze_fences then
503 for i = 1 , size do
504 local entry = list [ i ]
505 if entry . level % 2 = = 1 then
506 if entry . mirror and not entry . paired then
507 entry . mirror = false
508 end
509 elseif entry . mirror then
510 entry . mirror = false
511 end
512 end
513 else
514 for i = 1 , size do
515 local entry = list [ i ]
516 if entry . level % 2 = = 1 then
517 local mirror = mirrordata [ entry . char ]
518 if mirror then
519 entry . mirror = mirror
520 end
521 end
522 end
523 end
524end
525
526local function process ( head , direction )
527 local list , size = build_list ( head )
528 local baselevel = get_baselevel ( list , size , direction )
529 resolve_explicit ( list , size , baselevel )
530 resolve_levels ( list , size , baselevel , analyze_fences )
531 return list , size
532end
533
534return {
535 process = process ,
536}
537 |