You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
203 lines
6.1 KiB
203 lines
6.1 KiB
--
|
|
-- 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-2020 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 == luatexbase.registernumber'bbl@attr@dir' then
|
|
attr_dir = at.value % 3
|
|
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
|
|
|
|
|