-- -- This is file `babel-bidi-basic-r.lua', -- generated with the docstrip utility. -- -- The original source files were: -- -- babel.dtx (with options: `basic-r') -- -- -- Copyright (C) 2012-2023 Javier Bezos and Johannes L. Braams. -- Copyright (C) 1989-2012 Johannes L. Braams and -- any individual authors listed elsewhere in this file. -- All rights reserved. -- -- -- This file is part of the Babel system. -- -------------------------------------- -- -- It may be distributed and/or modified under the -- conditions of the LaTeX Project Public License, either version 1.3 -- of this license or (at your option) any later version. -- The latest version of this license is in -- http://www.latex-project.org/lppl.txt -- and version 1.3 or later is part of all distributions of LaTeX -- version 2003/12/01 or later. -- -- This work has the LPPL maintenance status "maintained". -- -- The Current Maintainer of this work is Javier Bezos. -- -- The list of derived (unpacked) files belonging to the distribution -- and covered by LPPL is defined by the unpacking scripts (with -- extension |.ins|) which are part of the distribution. -- Babel = Babel or {} Babel.bidi_enabled = true require('babel-data-bidi.lua') local characters = Babel.characters local ranges = Babel.ranges local DIR = node.id("dir") local function dir_mark(head, from, to, outer) dir = (outer == 'r') and 'TLT' or 'TRT' -- ie, reverse local d = node.new(DIR) d.dir = '+' .. dir node.insert_before(head, from, d) d = node.new(DIR) d.dir = '-' .. dir node.insert_after(head, to, d) end function Babel.bidi(head, ispar) local first_n, last_n -- first and last char with nums local last_es -- an auxiliary 'last' used with nums local first_d, last_d -- first and last char in L/R block local dir, dir_real local strong = ('TRT' == tex.pardir) and 'r' or 'l' local strong_lr = (strong == 'l') and 'l' or 'r' local outer = strong local new_dir = false local first_dir = false local inmath = false local last_lr local type_n = '' for item in node.traverse(head) do -- three cases: glyph, dir, otherwise if item.id == node.id'glyph' or (item.id == 7 and item.subtype == 2) then local itemchar if item.id == 7 and item.subtype == 2 then itemchar = item.replace.char else itemchar = item.char end local chardata = characters[itemchar] dir = chardata and chardata.d or nil if not dir then for nn, et in ipairs(ranges) do if itemchar < et[1] then break elseif itemchar <= et[2] then dir = et[3] break end end end dir = dir or 'l' if inmath then dir = ('TRT' == tex.mathdir) and 'r' or 'l' end if new_dir then attr_dir = 0 for at in node.traverse(item.attr) do if at.number == Babel.attr_dir then attr_dir = at.value & 0x3 end end if attr_dir == 1 then strong = 'r' elseif attr_dir == 2 then strong = 'al' else strong = 'l' end strong_lr = (strong == 'l') and 'l' or 'r' outer = strong_lr new_dir = false end if dir == 'nsm' then dir = strong end -- W1 dir_real = dir -- We need dir_real to set strong below if dir == 'al' then dir = 'r' end -- W3 if strong == 'al' then if dir == 'en' then dir = 'an' end -- W2 if dir == 'et' or dir == 'es' then dir = 'on' end -- W6 strong_lr = 'r' -- W3 end elseif item.id == node.id'dir' and not inmath then new_dir = true dir = nil elseif item.id == node.id'math' then inmath = (item.subtype == 0) else dir = nil -- Not a char end if dir == 'en' or dir == 'an' or dir == 'et' then if dir ~= 'et' then type_n = dir end first_n = first_n or item last_n = last_es or item last_es = nil elseif dir == 'es' and last_n then -- W3+W6 last_es = item elseif dir == 'cs' then -- it's right - do nothing elseif first_n then -- & if dir = any but en, et, an, es, cs, inc nil if strong_lr == 'r' and type_n ~= '' then dir_mark(head, first_n, last_n, 'r') elseif strong_lr == 'l' and first_d and type_n == 'an' then dir_mark(head, first_n, last_n, 'r') dir_mark(head, first_d, last_d, outer) first_d, last_d = nil, nil elseif strong_lr == 'l' and type_n ~= '' then last_d = last_n end type_n = '' first_n, last_n = nil, nil end if dir == 'l' or dir == 'r' then if dir ~= outer then first_d = first_d or item last_d = item elseif first_d and dir ~= strong_lr then dir_mark(head, first_d, last_d, outer) first_d, last_d = nil, nil end end if dir and not last_lr and dir ~= 'l' and outer == 'r' then item.char = characters[item.char] and characters[item.char].m or item.char elseif (dir or new_dir) and last_lr ~= item then local mir = outer .. strong_lr .. (dir or outer) if mir == 'rrr' or mir == 'lrr' or mir == 'rrl' or mir == 'rlr' then for ch in node.traverse(node.next(last_lr)) do if ch == item then break end if ch.id == node.id'glyph' and characters[ch.char] then ch.char = characters[ch.char].m or ch.char end end end end if dir == 'l' or dir == 'r' then last_lr = item strong = dir_real -- Don't search back - best save now strong_lr = (strong == 'l') and 'l' or 'r' elseif new_dir then last_lr = nil end end if last_lr and outer == 'r' then for ch in node.traverse_id(node.id'glyph', node.next(last_lr)) do if characters[ch.char] then ch.char = characters[ch.char].m or ch.char end end end if first_n then dir_mark(head, first_n, last_n, outer) end if first_d then dir_mark(head, first_d, last_d, outer) end return node.prev(head) or head end