%% %% This is file `luababel.def', %% generated with the docstrip utility. %% %% The original source files were: %% %% babel.dtx (with options: `luatex') %% %% %% Copyright (C) 2012-2022 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. %% \ifx\AddBabelHook\@undefined % When plain.def, babel.sty starts \bbl@trace{Read language.dat} \ifx\bbl@readstream\@undefined \csname newread\endcsname\bbl@readstream \fi \begingroup \toks@{} \count@\z@ % 0=start, 1=0th, 2=normal \def\bbl@process@line#1#2 #3 #4 {% \ifx=#1% \bbl@process@synonym{#2}% \else \bbl@process@language{#1#2}{#3}{#4}% \fi \ignorespaces} \def\bbl@manylang{% \ifnum\bbl@last>\@ne \bbl@info{Non-standard hyphenation setup}% \fi \let\bbl@manylang\relax} \def\bbl@process@language#1#2#3{% \ifcase\count@ \@ifundefined{zth@#1}{\count@\tw@}{\count@\@ne}% \or \count@\tw@ \fi \ifnum\count@=\tw@ \expandafter\addlanguage\csname l@#1\endcsname \language\allocationnumber \chardef\bbl@last\allocationnumber \bbl@manylang \let\bbl@elt\relax \xdef\bbl@languages{% \bbl@languages\bbl@elt{#1}{\the\language}{#2}{#3}}% \fi \the\toks@ \toks@{}} \def\bbl@process@synonym@aux#1#2{% \global\expandafter\chardef\csname l@#1\endcsname#2\relax \let\bbl@elt\relax \xdef\bbl@languages{% \bbl@languages\bbl@elt{#1}{#2}{}{}}}% \def\bbl@process@synonym#1{% \ifcase\count@ \toks@\expandafter{\the\toks@\relax\bbl@process@synonym{#1}}% \or \@ifundefined{zth@#1}{\bbl@process@synonym@aux{#1}{0}}{}% \else \bbl@process@synonym@aux{#1}{\the\bbl@last}% \fi} \ifx\bbl@languages\@undefined % Just a (sensible?) guess \chardef\l@english\z@ \chardef\l@USenglish\z@ \chardef\bbl@last\z@ \global\@namedef{bbl@hyphendata@0}{{hyphen.tex}{}} \gdef\bbl@languages{% \bbl@elt{english}{0}{hyphen.tex}{}% \bbl@elt{USenglish}{0}{}{}} \else \global\let\bbl@languages@format\bbl@languages \def\bbl@elt#1#2#3#4{% Remove all except language 0 \ifnum#2>\z@\else \noexpand\bbl@elt{#1}{#2}{#3}{#4}% \fi}% \xdef\bbl@languages{\bbl@languages}% \fi \def\bbl@elt#1#2#3#4{\@namedef{zth@#1}{}} % Define flags \bbl@languages \openin\bbl@readstream=language.dat \ifeof\bbl@readstream \bbl@warning{I couldn't find language.dat. No additional\\% patterns loaded. Reported}% \else \loop \endlinechar\m@ne \read\bbl@readstream to \bbl@line \endlinechar`\^^M \if T\ifeof\bbl@readstream F\fi T\relax \ifx\bbl@line\@empty\else \edef\bbl@line{\bbl@line\space\space\space}% \expandafter\bbl@process@line\bbl@line\relax \fi \repeat \fi \endgroup \bbl@trace{Macros for reading patterns files} \def\bbl@get@enc#1:#2:#3\@@@{\def\bbl@hyph@enc{#2}} \ifx\babelcatcodetablenum\@undefined \ifx\newcatcodetable\@undefined \def\babelcatcodetablenum{5211} \def\bbl@pattcodes{\numexpr\babelcatcodetablenum+1\relax} \else \newcatcodetable\babelcatcodetablenum \newcatcodetable\bbl@pattcodes \fi \else \def\bbl@pattcodes{\numexpr\babelcatcodetablenum+1\relax} \fi \def\bbl@luapatterns#1#2{% \bbl@get@enc#1::\@@@ \setbox\z@\hbox\bgroup \begingroup \savecatcodetable\babelcatcodetablenum\relax \initcatcodetable\bbl@pattcodes\relax \catcodetable\bbl@pattcodes\relax \catcode`\#=6 \catcode`\$=3 \catcode`\&=4 \catcode`\^=7 \catcode`\_=8 \catcode`\{=1 \catcode`\}=2 \catcode`\~=13 \catcode`\@=11 \catcode`\^^I=10 \catcode`\^^J=12 \catcode`\<=12 \catcode`\>=12 \catcode`\*=12 \catcode`\.=12 \catcode`\-=12 \catcode`\/=12 \catcode`\[=12 \catcode`\]=12 \catcode`\`=12 \catcode`\'=12 \catcode`\"=12 \input #1\relax \catcodetable\babelcatcodetablenum\relax \endgroup \def\bbl@tempa{#2}% \ifx\bbl@tempa\@empty\else \input #2\relax \fi \egroup}% \def\bbl@patterns@lua#1{% \language=\expandafter\ifx\csname l@#1:\f@encoding\endcsname\relax \csname l@#1\endcsname \edef\bbl@tempa{#1}% \else \csname l@#1:\f@encoding\endcsname \edef\bbl@tempa{#1:\f@encoding}% \fi\relax \@namedef{lu@texhyphen@loaded@\the\language}{}% Temp \@ifundefined{bbl@hyphendata@\the\language}% {\def\bbl@elt##1##2##3##4{% \ifnum##2=\csname l@\bbl@tempa\endcsname % #2=spanish, dutch:OT1... \def\bbl@tempb{##3}% \ifx\bbl@tempb\@empty\else % if not a synonymous \def\bbl@tempc{{##3}{##4}}% \fi \bbl@csarg\xdef{hyphendata@##2}{\bbl@tempc}% \fi}% \bbl@languages \@ifundefined{bbl@hyphendata@\the\language}% {\bbl@info{No hyphenation patterns were set for\\% language '\bbl@tempa'. Reported}}% {\expandafter\expandafter\expandafter\bbl@luapatterns \csname bbl@hyphendata@\the\language\endcsname}}{}} \endinput\fi % Here ends \ifx\AddBabelHook\@undefined % A few lines are only read by hyphen.cfg \ifx\DisableBabelHook\@undefined \AddBabelHook{luatex}{everylanguage}{% \def\process@language##1##2##3{% \def\process@line####1####2 ####3 ####4 {}}} \AddBabelHook{luatex}{loadpatterns}{% \input #1\relax \expandafter\gdef\csname bbl@hyphendata@\the\language\endcsname {{#1}{}}} \AddBabelHook{luatex}{loadexceptions}{% \input #1\relax \def\bbl@tempb##1##2{{##1}{#1}}% \expandafter\xdef\csname bbl@hyphendata@\the\language\endcsname {\expandafter\expandafter\expandafter\bbl@tempb \csname bbl@hyphendata@\the\language\endcsname}} \endinput\fi % Here stops reading code for hyphen.cfg % The following is read the 2nd time it's loaded \begingroup % TODO - to a lua file \catcode`\%=12 \catcode`\'=12 \catcode`\"=12 \catcode`\:=12 \directlua{ Babel = Babel or {} function Babel.bytes(line) return line:gsub("(.)", function (chr) return unicode.utf8.char(string.byte(chr)) end) end function Babel.begin_process_input() if luatexbase and luatexbase.add_to_callback then luatexbase.add_to_callback('process_input_buffer', Babel.bytes,'Babel.bytes') else Babel.callback = callback.find('process_input_buffer') callback.register('process_input_buffer',Babel.bytes) end end function Babel.end_process_input () if luatexbase and luatexbase.remove_from_callback then luatexbase.remove_from_callback('process_input_buffer','Babel.bytes') else callback.register('process_input_buffer',Babel.callback) end end function Babel.addpatterns(pp, lg) local lg = lang.new(lg) local pats = lang.patterns(lg) or '' lang.clear_patterns(lg) for p in pp:gmatch('[^%s]+') do ss = '' for i in string.utfcharacters(p:gsub('%d', '')) do ss = ss .. '%d?' .. i end ss = ss:gsub('^%%d%?%.', '%%.') .. '%d?' ss = ss:gsub('%.%%d%?$', '%%.') pats, n = pats:gsub('%s' .. ss .. '%s', ' ' .. p .. ' ') if n == 0 then tex.sprint( [[\string\csname\space bbl@info\endcsname{New pattern: ]] .. p .. [[}]]) pats = pats .. ' ' .. p else tex.sprint( [[\string\csname\space bbl@info\endcsname{Renew pattern: ]] .. p .. [[}]]) end end lang.patterns(lg, pats) end function Babel.hlist_has_bidi(head) local has_bidi = false for item in node.traverse(head) do if item.id == node.id'glyph' then local itemchar = item.char local chardata = Babel.characters[itemchar] local dir = chardata and chardata.d or nil if not dir then for nn, et in ipairs(Babel.ranges) do if itemchar < et[1] then break elseif itemchar <= et[2] then dir = et[3] break end end end if dir and (dir == 'al' or dir == 'r') then has_bidi = true end end end return has_bidi end function Babel.set_chranges_b (script, chrng) if chrng == '' then return end texio.write('Replacing ' .. script .. ' script ranges') Babel.script_blocks[script] = {} for s, e in string.gmatch(chrng..' ', '(.-)%.%.(.-)%s') do table.insert( Babel.script_blocks[script], {tonumber(s,16), tonumber(e,16)}) end end } \endgroup \ifx\newattribute\@undefined\else \newattribute\bbl@attr@locale \directlua{ Babel.attr_locale = luatexbase.registernumber'bbl@attr@locale' } \AddBabelHook{luatex}{beforeextras}{% \setattribute\bbl@attr@locale\localeid} \fi \def\BabelStringsDefault{unicode} \let\luabbl@stop\relax \AddBabelHook{luatex}{encodedcommands}{% \def\bbl@tempa{utf8}\def\bbl@tempb{#1}% \ifx\bbl@tempa\bbl@tempb\else \directlua{Babel.begin_process_input()}% \def\luabbl@stop{% \directlua{Babel.end_process_input()}}% \fi}% \AddBabelHook{luatex}{stopcommands}{% \luabbl@stop \let\luabbl@stop\relax} \AddBabelHook{luatex}{patterns}{% \@ifundefined{bbl@hyphendata@\the\language}% {\def\bbl@elt##1##2##3##4{% \ifnum##2=\csname l@#2\endcsname % #2=spanish, dutch:OT1... \def\bbl@tempb{##3}% \ifx\bbl@tempb\@empty\else % if not a synonymous \def\bbl@tempc{{##3}{##4}}% \fi \bbl@csarg\xdef{hyphendata@##2}{\bbl@tempc}% \fi}% \bbl@languages \@ifundefined{bbl@hyphendata@\the\language}% {\bbl@info{No hyphenation patterns were set for\\% language '#2'. Reported}}% {\expandafter\expandafter\expandafter\bbl@luapatterns \csname bbl@hyphendata@\the\language\endcsname}}{}% \@ifundefined{bbl@patterns@}{}{% \begingroup \bbl@xin@{,\number\language,}{,\bbl@pttnlist}% \ifin@\else \ifx\bbl@patterns@\@empty\else \directlua{ Babel.addpatterns( [[\bbl@patterns@]], \number\language) }% \fi \@ifundefined{bbl@patterns@#1}% \@empty {\directlua{ Babel.addpatterns( [[\space\csname bbl@patterns@#1\endcsname]], \number\language) }}% \xdef\bbl@pttnlist{\bbl@pttnlist\number\language,}% \fi \endgroup}% \bbl@exp{% \bbl@ifunset{bbl@prehc@\languagename}{}% {\\\bbl@ifblank{\bbl@cs{prehc@\languagename}}{}% {\prehyphenchar=\bbl@cl{prehc}\relax}}}} \@onlypreamble\babelpatterns \AtEndOfPackage{% \newcommand\babelpatterns[2][\@empty]{% \ifx\bbl@patterns@\relax \let\bbl@patterns@\@empty \fi \ifx\bbl@pttnlist\@empty\else \bbl@warning{% You must not intermingle \string\selectlanguage\space and\\% \string\babelpatterns\space or some patterns will not\\% be taken into account. Reported}% \fi \ifx\@empty#1% \protected@edef\bbl@patterns@{\bbl@patterns@\space#2}% \else \edef\bbl@tempb{\zap@space#1 \@empty}% \bbl@for\bbl@tempa\bbl@tempb{% \bbl@fixname\bbl@tempa \bbl@iflanguage\bbl@tempa{% \bbl@csarg\protected@edef{patterns@\bbl@tempa}{% \@ifundefined{bbl@patterns@\bbl@tempa}% \@empty {\csname bbl@patterns@\bbl@tempa\endcsname\space}% #2}}}% \fi}} \directlua{ Babel = Babel or {} Babel.linebreaking = Babel.linebreaking or {} Babel.linebreaking.before = {} Babel.linebreaking.after = {} Babel.locale = {} % Free to use, indexed by \localeid function Babel.linebreaking.add_before(func) tex.print([[\noexpand\csname bbl@luahyphenate\endcsname]]) table.insert(Babel.linebreaking.before, func) end function Babel.linebreaking.add_after(func) tex.print([[\noexpand\csname bbl@luahyphenate\endcsname]]) table.insert(Babel.linebreaking.after, func) end } \def\bbl@intraspace#1 #2 #3\@@{% \directlua{ Babel = Babel or {} Babel.intraspaces = Babel.intraspaces or {} Babel.intraspaces['\csname bbl@sbcp@\languagename\endcsname'] = % {b = #1, p = #2, m = #3} Babel.locale_props[\the\localeid].intraspace = % {b = #1, p = #2, m = #3} }} \def\bbl@intrapenalty#1\@@{% \directlua{ Babel = Babel or {} Babel.intrapenalties = Babel.intrapenalties or {} Babel.intrapenalties['\csname bbl@sbcp@\languagename\endcsname'] = #1 Babel.locale_props[\the\localeid].intrapenalty = #1 }} \begingroup \catcode`\%=12 \catcode`\^=14 \catcode`\'=12 \catcode`\~=12 \gdef\bbl@seaintraspace{^ \let\bbl@seaintraspace\relax \directlua{ Babel = Babel or {} Babel.sea_enabled = true Babel.sea_ranges = Babel.sea_ranges or {} function Babel.set_chranges (script, chrng) local c = 0 for s, e in string.gmatch(chrng..' ', '(.-)%.%.(.-)%s') do Babel.sea_ranges[script..c]={tonumber(s,16), tonumber(e,16)} c = c + 1 end end function Babel.sea_disc_to_space (head) local sea_ranges = Babel.sea_ranges local last_char = nil local quad = 655360 ^% 10 pt = 655360 = 10 * 65536 for item in node.traverse(head) do local i = item.id if i == node.id'glyph' then last_char = item elseif i == 7 and item.subtype == 3 and last_char and last_char.char > 0x0C99 then quad = font.getfont(last_char.font).size for lg, rg in pairs(sea_ranges) do if last_char.char > rg[1] and last_char.char < rg[2] then lg = lg:sub(1, 4) ^% Remove trailing number of, eg, Cyrl1 local intraspace = Babel.intraspaces[lg] local intrapenalty = Babel.intrapenalties[lg] local n if intrapenalty ~= 0 then n = node.new(14, 0) ^% penalty n.penalty = intrapenalty node.insert_before(head, item, n) end n = node.new(12, 13) ^% (glue, spaceskip) node.setglue(n, intraspace.b * quad, intraspace.p * quad, intraspace.m * quad) node.insert_before(head, item, n) node.remove(head, item) end end end end end }^^ \bbl@luahyphenate} \catcode`\%=14 \gdef\bbl@cjkintraspace{% \let\bbl@cjkintraspace\relax \directlua{ Babel = Babel or {} require('babel-data-cjk.lua') Babel.cjk_enabled = true function Babel.cjk_linebreak(head) local GLYPH = node.id'glyph' local last_char = nil local quad = 655360 % 10 pt = 655360 = 10 * 65536 local last_class = nil local last_lang = nil for item in node.traverse(head) do if item.id == GLYPH then local lang = item.lang local LOCALE = node.get_attribute(item, Babel.attr_locale) local props = Babel.locale_props[LOCALE] local class = Babel.cjk_class[item.char].c if props.cjk_quotes and props.cjk_quotes[item.char] then class = props.cjk_quotes[item.char] end if class == 'cp' then class = 'cl' end % )] as CL if class == 'id' then class = 'I' end local br = 0 if class and last_class and Babel.cjk_breaks[last_class][class] then br = Babel.cjk_breaks[last_class][class] end if br == 1 and props.linebreak == 'c' and lang ~= \the\l@nohyphenation\space and last_lang ~= \the\l@nohyphenation then local intrapenalty = props.intrapenalty if intrapenalty ~= 0 then local n = node.new(14, 0) % penalty n.penalty = intrapenalty node.insert_before(head, item, n) end local intraspace = props.intraspace local n = node.new(12, 13) % (glue, spaceskip) node.setglue(n, intraspace.b * quad, intraspace.p * quad, intraspace.m * quad) node.insert_before(head, item, n) end if font.getfont(item.font) then quad = font.getfont(item.font).size end last_class = class last_lang = lang else % if penalty, glue or anything else last_class = nil end end lang.hyphenate(head) end }% \bbl@luahyphenate} \gdef\bbl@luahyphenate{% \let\bbl@luahyphenate\relax \directlua{ luatexbase.add_to_callback('hyphenate', function (head, tail) if Babel.linebreaking.before then for k, func in ipairs(Babel.linebreaking.before) do func(head) end end if Babel.cjk_enabled then Babel.cjk_linebreak(head) end lang.hyphenate(head) if Babel.linebreaking.after then for k, func in ipairs(Babel.linebreaking.after) do func(head) end end if Babel.sea_enabled then Babel.sea_disc_to_space(head) end end, 'Babel.hyphenate') } } \endgroup \def\bbl@provide@intraspace{% \bbl@ifunset{bbl@intsp@\languagename}{}% {\expandafter\ifx\csname bbl@intsp@\languagename\endcsname\@empty\else \bbl@xin@{/c}{/\bbl@cl{lnbrk}}% \ifin@ % cjk \bbl@cjkintraspace \directlua{ Babel = Babel or {} Babel.locale_props = Babel.locale_props or {} Babel.locale_props[\the\localeid].linebreak = 'c' }% \bbl@exp{\\\bbl@intraspace\bbl@cl{intsp}\\\@@}% \ifx\bbl@KVP@intrapenalty\@nil \bbl@intrapenalty0\@@ \fi \else % sea \bbl@seaintraspace \bbl@exp{\\\bbl@intraspace\bbl@cl{intsp}\\\@@}% \directlua{ Babel = Babel or {} Babel.sea_ranges = Babel.sea_ranges or {} Babel.set_chranges('\bbl@cl{sbcp}', '\bbl@cl{chrng}') }% \ifx\bbl@KVP@intrapenalty\@nil \bbl@intrapenalty0\@@ \fi \fi \fi \ifx\bbl@KVP@intrapenalty\@nil\else \expandafter\bbl@intrapenalty\bbl@KVP@intrapenalty\@@ \fi}} \ifnum\bbl@bidimode>100 \ifnum\bbl@bidimode<200 \def\bblar@chars{% 0628,0629,062A,062B,062C,062D,062E,062F,0630,0631,0632,0633,% 0634,0635,0636,0637,0638,0639,063A,063B,063C,063D,063E,063F,% 0640,0641,0642,0643,0644,0645,0646,0647,0649} \def\bblar@elongated{% 0626,0628,062A,062B,0633,0634,0635,0636,063B,% 063C,063D,063E,063F,0641,0642,0643,0644,0646,% 0649,064A} \begingroup \catcode`_=11 \catcode`:=11 \gdef\bblar@nofswarn{\gdef\msg_warning:nnx##1##2##3{}} \endgroup \gdef\bbl@arabicjust{% \let\bbl@arabicjust\relax \newattribute\bblar@kashida \directlua{ Babel.attr_kashida = luatexbase.registernumber'bblar@kashida' }% \bblar@kashida=\z@ \bbl@patchfont{{\bbl@parsejalt}}% \directlua{ Babel.arabic.elong_map = Babel.arabic.elong_map or {} Babel.arabic.elong_map[\the\localeid] = {} luatexbase.add_to_callback('post_linebreak_filter', Babel.arabic.justify, 'Babel.arabic.justify') luatexbase.add_to_callback('hpack_filter', Babel.arabic.justify_hbox, 'Babel.arabic.justify_hbox') }}% \def\bblar@fetchjalt#1#2#3#4{% \bbl@exp{\\\bbl@foreach{#1}}{% \bbl@ifunset{bblar@JE@##1}% {\setbox\z@\hbox{^^^^200d\char"##1#2}}% {\setbox\z@\hbox{^^^^200d\char"\@nameuse{bblar@JE@##1}#2}}% \directlua{% local last = nil for item in node.traverse(tex.box[0].head) do if item.id == node.id'glyph' and item.char > 0x600 and not (item.char == 0x200D) then last = item end end Babel.arabic.#3['##1#4'] = last.char }}} \gdef\bbl@parsejalt{% \ifx\addfontfeature\@undefined\else \bbl@xin@{/e}{/\bbl@cl{lnbrk}}% \ifin@ \directlua{% if Babel.arabic.elong_map[\the\localeid][\fontid\font] == nil then Babel.arabic.elong_map[\the\localeid][\fontid\font] = {} tex.print([[\string\csname\space bbl@parsejalti\endcsname]]) end }% \fi \fi} \gdef\bbl@parsejalti{% \begingroup \let\bbl@parsejalt\relax % To avoid infinite loop \edef\bbl@tempb{\fontid\font}% \bblar@nofswarn \bblar@fetchjalt\bblar@elongated{}{from}{}% \bblar@fetchjalt\bblar@chars{^^^^064a}{from}{a}% Alef maksura \bblar@fetchjalt\bblar@chars{^^^^0649}{from}{y}% Yeh \addfontfeature{RawFeature=+jalt}% % \@namedef{bblar@JE@0643}{06AA}% todo: catch medial kaf \bblar@fetchjalt\bblar@elongated{}{dest}{}% \bblar@fetchjalt\bblar@chars{^^^^064a}{dest}{a}% \bblar@fetchjalt\bblar@chars{^^^^0649}{dest}{y}% \directlua{% for k, v in pairs(Babel.arabic.from) do if Babel.arabic.dest[k] and not (Babel.arabic.from[k] == Babel.arabic.dest[k]) then Babel.arabic.elong_map[\the\localeid][\bbl@tempb] [Babel.arabic.from[k]] = Babel.arabic.dest[k] end end }% \endgroup} \begingroup \catcode`#=11 \catcode`~=11 \directlua{ Babel.arabic = Babel.arabic or {} Babel.arabic.from = {} Babel.arabic.dest = {} Babel.arabic.justify_factor = 0.95 Babel.arabic.justify_enabled = true function Babel.arabic.justify(head) if not Babel.arabic.justify_enabled then return head end for line in node.traverse_id(node.id'hlist', head) do Babel.arabic.justify_hlist(head, line) end return head end function Babel.arabic.justify_hbox(head, gc, size, pack) local has_inf = false if Babel.arabic.justify_enabled and pack == 'exactly' then for n in node.traverse_id(12, head) do if n.stretch_order > 0 then has_inf = true end end if not has_inf then Babel.arabic.justify_hlist(head, nil, gc, size, pack) end end return head end function Babel.arabic.justify_hlist(head, line, gc, size, pack) local d, new local k_list, k_item, pos_inline local width, width_new, full, k_curr, wt_pos, goal, shift local subst_done = false local elong_map = Babel.arabic.elong_map local last_line local GLYPH = node.id'glyph' local KASHIDA = Babel.attr_kashida local LOCALE = Babel.attr_locale if line == nil then line = {} line.glue_sign = 1 line.glue_order = 0 line.head = head line.shift = 0 line.width = size end % Exclude last line. todo. But-- it discards one-word lines, too! % ? Look for glue = 12:15 if (line.glue_sign == 1 and line.glue_order == 0) then elongs = {} % Stores elongated candidates of each line k_list = {} % And all letters with kashida pos_inline = 0 % Not yet used for n in node.traverse_id(GLYPH, line.head) do pos_inline = pos_inline + 1 % To find where it is. Not used. % Elongated glyphs if elong_map then local locale = node.get_attribute(n, LOCALE) if elong_map[locale] and elong_map[locale][n.font] and elong_map[locale][n.font][n.char] then table.insert(elongs, {node = n, locale = locale} ) node.set_attribute(n.prev, KASHIDA, 0) end end % Tatwil if Babel.kashida_wts then local k_wt = node.get_attribute(n, KASHIDA) if k_wt > 0 then % todo. parameter for multi inserts table.insert(k_list, {node = n, weight = k_wt, pos = pos_inline}) end end end % of node.traverse_id if #elongs == 0 and #k_list == 0 then goto next_line end full = line.width shift = line.shift goal = full * Babel.arabic.justify_factor % A bit crude width = node.dimensions(line.head) % The 'natural' width % == Elongated == % Original idea taken from 'chikenize' while (#elongs > 0 and width < goal) do subst_done = true local x = #elongs local curr = elongs[x].node local oldchar = curr.char curr.char = elong_map[elongs[x].locale][curr.font][curr.char] width = node.dimensions(line.head) % Check if the line is too wide % Substitute back if the line would be too wide and break: if width > goal then curr.char = oldchar break end % If continue, pop the just substituted node from the list: table.remove(elongs, x) end % == Tatwil == if #k_list == 0 then goto next_line end width = node.dimensions(line.head) % The 'natural' width k_curr = #k_list wt_pos = 1 while width < goal do subst_done = true k_item = k_list[k_curr].node if k_list[k_curr].weight == Babel.kashida_wts[wt_pos] then d = node.copy(k_item) d.char = 0x0640 line.head, new = node.insert_after(line.head, k_item, d) width_new = node.dimensions(line.head) if width > goal or width == width_new then node.remove(line.head, new) % Better compute before break end width = width_new end if k_curr == 1 then k_curr = #k_list wt_pos = (wt_pos >= table.getn(Babel.kashida_wts)) and 1 or wt_pos+1 else k_curr = k_curr - 1 end end ::next_line:: % Must take into account marks and ins, see luatex manual. % Have to be executed only if there are changes. Investigate % what's going on exactly. if subst_done and not gc then d = node.hpack(line.head, full, 'exactly') d.shift = shift node.insert_before(head, line, d) node.remove(head, line) end end % if process line end } \endgroup \fi\fi % Arabic just block \AddBabelHook{babel-fontspec}{afterextras}{\bbl@switchfont} \AddBabelHook{babel-fontspec}{beforestart}{\bbl@ckeckstdfonts} \DisableBabelHook{babel-fontspec} \bbl@trace{Font handling with fontspec} \ifx\ExplSyntaxOn\@undefined\else \ExplSyntaxOn \catcode`\ =10 \def\bbl@loadfontspec{% \usepackage{fontspec}% TODO. Apply patch always \expandafter \def\csname msg~text~>~fontspec/language-not-exist\endcsname##1##2##3##4{% Font '\l_fontspec_fontname_tl' is using the\\% default features for language '##1'.\\% That's usually fine, because many languages\\% require no specific features, but if the output is\\% not as expected, consider selecting another font.} \expandafter \def\csname msg~text~>~fontspec/no-script\endcsname##1##2##3##4{% Font '\l_fontspec_fontname_tl' is using the\\% default features for script '##2'.\\% That's not always wrong, but if the output is\\% not as expected, consider selecting another font.}} \ExplSyntaxOff \fi \@onlypreamble\babelfont \newcommand\babelfont[2][]{% 1=langs/scripts 2=fam \bbl@foreach{#1}{% \expandafter\ifx\csname date##1\endcsname\relax \IfFileExists{babel-##1.tex}% {\babelprovide{##1}}% {}% \fi}% \edef\bbl@tempa{#1}% \def\bbl@tempb{#2}% Used by \bbl@bblfont \ifx\fontspec\@undefined \bbl@loadfontspec \fi \EnableBabelHook{babel-fontspec}% Just calls \bbl@switchfont \bbl@bblfont} \newcommand\bbl@bblfont[2][]{% 1=features 2=fontname, @font=rm|sf|tt \bbl@ifunset{\bbl@tempb family}% {\bbl@providefam{\bbl@tempb}}% {}% % For the default font, just in case: \bbl@ifunset{bbl@lsys@\languagename}{\bbl@provide@lsys{\languagename}}{}% \expandafter\bbl@ifblank\expandafter{\bbl@tempa}% {\bbl@csarg\edef{\bbl@tempb dflt@}{<>{#1}{#2}}% save bbl@rmdflt@ \bbl@exp{% \let\\% \\\bbl@font@set\% \<\bbl@tempb default>\<\bbl@tempb family>}}% {\bbl@foreach\bbl@tempa{% ie bbl@rmdflt@lang / *scrt \bbl@csarg\def{\bbl@tempb dflt@##1}{<>{#1}{#2}}}}}% \def\bbl@providefam#1{% \bbl@exp{% \\\newcommand\<#1default>{}% Just define it \\\bbl@add@list\\\bbl@font@fams{#1}% \\\DeclareRobustCommand\<#1family>{% \\\not@math@alphabet\<#1family>\relax % \\\prepare@family@series@update{#1}\<#1default>% TODO. Fails \\\fontfamily\<#1default>% \\\\UseHooks\\\@undefined\\\\UseHook{#1family}\% \\\selectfont}% \\\DeclareTextFontCommand{\}{\<#1family>}}} \def\bbl@nostdfont#1{% \bbl@ifunset{bbl@WFF@\f@family}% {\bbl@csarg\gdef{WFF@\f@family}{}% Flag, to avoid dupl warns \bbl@infowarn{The current font is not a babel standard family:\\% #1% \fontname\font\\% There is nothing intrinsically wrong with this warning, and\\% you can ignore it altogether if you do not need these\\% families. But if they are used in the document, you should be\\% aware 'babel' will not set Script and Language for them, so\\% you may consider defining a new family with \string\babelfont.\\% See the manual for further details about \string\babelfont.\\% Reported}} {}}% \gdef\bbl@switchfont{% \bbl@ifunset{bbl@lsys@\languagename}{\bbl@provide@lsys{\languagename}}{}% \bbl@exp{% eg Arabic -> arabic \lowercase{\edef\\\bbl@tempa{\bbl@cl{sname}}}}% \bbl@foreach\bbl@font@fams{% \bbl@ifunset{bbl@##1dflt@\languagename}% (1) language? {\bbl@ifunset{bbl@##1dflt@*\bbl@tempa}% (2) from script? {\bbl@ifunset{bbl@##1dflt@}% 2=F - (3) from generic? {}% 123=F - nothing! {\bbl@exp{% 3=T - from generic \global\let\% \}}}% {\bbl@exp{% 2=T - from script \global\let\% \}}}% {}}% 1=T - language, already defined \def\bbl@tempa{\bbl@nostdfont{}}% \bbl@foreach\bbl@font@fams{% don't gather with prev for \bbl@ifunset{bbl@##1dflt@\languagename}% {\bbl@cs{famrst@##1}% \global\bbl@csarg\let{famrst@##1}\relax}% {\bbl@exp{% order is relevant. TODO: but sometimes wrong! \\\bbl@add\\\originalTeX{% \\\bbl@font@rst{\bbl@cl{##1dflt}}% \<##1default>\<##1family>{##1}}% \\\bbl@font@set\% the main part! \<##1default>\<##1family>}}}% \bbl@ifrestoring{}{\bbl@tempa}}% \ifx\f@family\@undefined\else % if latex \ifcase\bbl@engine % if pdftex \let\bbl@ckeckstdfonts\relax \else \def\bbl@ckeckstdfonts{% \begingroup \global\let\bbl@ckeckstdfonts\relax \let\bbl@tempa\@empty \bbl@foreach\bbl@font@fams{% \bbl@ifunset{bbl@##1dflt@}% {\@nameuse{##1family}% \bbl@csarg\gdef{WFF@\f@family}{}% Flag \bbl@exp{\\\bbl@add\\\bbl@tempa{* \<##1family>= \f@family\\\\% \space\space\fontname\font\\\\}}% \bbl@csarg\xdef{##1dflt@}{\f@family}% \expandafter\xdef\csname ##1default\endcsname{\f@family}}% {}}% \ifx\bbl@tempa\@empty\else \bbl@infowarn{The following font families will use the default\\% settings for all or some languages:\\% \bbl@tempa There is nothing intrinsically wrong with it, but\\% 'babel' will no set Script and Language, which could\\% be relevant in some languages. If your document uses\\% these families, consider redefining them with \string\babelfont.\\% Reported}% \fi \endgroup} \fi \fi \def\bbl@font@set#1#2#3{% eg \bbl@rmdflt@lang \rmdefault \rmfamily \bbl@xin@{<>}{#1}% \ifin@ \bbl@exp{\\\bbl@fontspec@set\\#1\expandafter\@gobbletwo#1\\#3}% \fi \bbl@exp{% 'Unprotected' macros return prev values \def\\#2{#1}% eg, \rmdefault{\bbl@rmdflt@lang} \\\bbl@ifsamestring{#2}{\f@family}% {\\#3% \\\bbl@ifsamestring{\f@series}{\bfdefault}{\\\bfseries}{}% \let\\\bbl@tempa\relax}% {}}} \def\bbl@fontspec@set#1#2#3#4{% eg \bbl@rmdflt@lang fnt-opt fnt-nme \xxfamily \let\bbl@tempe\bbl@mapselect \let\bbl@mapselect\relax \let\bbl@temp@fam#4% eg, '\rmfamily', to be restored below \let#4\@empty % Make sure \renewfontfamily is valid \bbl@exp{% \let\\\bbl@temp@pfam\<\bbl@stripslash#4\space>% eg, '\rmfamily ' \{fontspec-opentype}{Script/\bbl@cl{sname}}% {\\\newfontscript{\bbl@cl{sname}}{\bbl@cl{sotf}}}% \{fontspec-opentype}{Language/\bbl@cl{lname}}% {\\\newfontlanguage{\bbl@cl{lname}}{\bbl@cl{lotf}}}% \\\renewfontfamily\\#4% [\bbl@cl{lsys},#2]}{#3}% ie \bbl@exp{..}{#3} \begingroup #4% \xdef#1{\f@family}% eg, \bbl@rmdflt@lang{FreeSerif(0)} \endgroup \let#4\bbl@temp@fam \bbl@exp{\let\<\bbl@stripslash#4\space>}\bbl@temp@pfam \let\bbl@mapselect\bbl@tempe}% \def\bbl@font@rst#1#2#3#4{% \bbl@csarg\def{famrst@#4}{\bbl@font@set{#1}#2#3}} \def\bbl@font@fams{rm,sf,tt} \directlua{ Babel.script_blocks = { ['dflt'] = {}, ['Arab'] = {{0x0600, 0x06FF}, {0x08A0, 0x08FF}, {0x0750, 0x077F}, {0xFE70, 0xFEFF}, {0xFB50, 0xFDFF}, {0x1EE00, 0x1EEFF}}, ['Armn'] = {{0x0530, 0x058F}}, ['Beng'] = {{0x0980, 0x09FF}}, ['Cher'] = {{0x13A0, 0x13FF}, {0xAB70, 0xABBF}}, ['Copt'] = {{0x03E2, 0x03EF}, {0x2C80, 0x2CFF}, {0x102E0, 0x102FF}}, ['Cyrl'] = {{0x0400, 0x04FF}, {0x0500, 0x052F}, {0x1C80, 0x1C8F}, {0x2DE0, 0x2DFF}, {0xA640, 0xA69F}}, ['Deva'] = {{0x0900, 0x097F}, {0xA8E0, 0xA8FF}}, ['Ethi'] = {{0x1200, 0x137F}, {0x1380, 0x139F}, {0x2D80, 0x2DDF}, {0xAB00, 0xAB2F}}, ['Geor'] = {{0x10A0, 0x10FF}, {0x2D00, 0x2D2F}}, % Don't follow strictly Unicode, which places some Coptic letters in % the 'Greek and Coptic' block ['Grek'] = {{0x0370, 0x03E1}, {0x03F0, 0x03FF}, {0x1F00, 0x1FFF}}, ['Hans'] = {{0x2E80, 0x2EFF}, {0x3000, 0x303F}, {0x31C0, 0x31EF}, {0x3300, 0x33FF}, {0x3400, 0x4DBF}, {0x4E00, 0x9FFF}, {0xF900, 0xFAFF}, {0xFE30, 0xFE4F}, {0xFF00, 0xFFEF}, {0x20000, 0x2A6DF}, {0x2A700, 0x2B73F}, {0x2B740, 0x2B81F}, {0x2B820, 0x2CEAF}, {0x2CEB0, 0x2EBEF}, {0x2F800, 0x2FA1F}}, ['Hebr'] = {{0x0590, 0x05FF}}, ['Jpan'] = {{0x3000, 0x303F}, {0x3040, 0x309F}, {0x30A0, 0x30FF}, {0x4E00, 0x9FAF}, {0xFF00, 0xFFEF}}, ['Khmr'] = {{0x1780, 0x17FF}, {0x19E0, 0x19FF}}, ['Knda'] = {{0x0C80, 0x0CFF}}, ['Kore'] = {{0x1100, 0x11FF}, {0x3000, 0x303F}, {0x3130, 0x318F}, {0x4E00, 0x9FAF}, {0xA960, 0xA97F}, {0xAC00, 0xD7AF}, {0xD7B0, 0xD7FF}, {0xFF00, 0xFFEF}}, ['Laoo'] = {{0x0E80, 0x0EFF}}, ['Latn'] = {{0x0000, 0x007F}, {0x0080, 0x00FF}, {0x0100, 0x017F}, {0x0180, 0x024F}, {0x1E00, 0x1EFF}, {0x2C60, 0x2C7F}, {0xA720, 0xA7FF}, {0xAB30, 0xAB6F}}, ['Mahj'] = {{0x11150, 0x1117F}}, ['Mlym'] = {{0x0D00, 0x0D7F}}, ['Mymr'] = {{0x1000, 0x109F}, {0xAA60, 0xAA7F}, {0xA9E0, 0xA9FF}}, ['Orya'] = {{0x0B00, 0x0B7F}}, ['Sinh'] = {{0x0D80, 0x0DFF}, {0x111E0, 0x111FF}}, ['Syrc'] = {{0x0700, 0x074F}, {0x0860, 0x086F}}, ['Taml'] = {{0x0B80, 0x0BFF}}, ['Telu'] = {{0x0C00, 0x0C7F}}, ['Tfng'] = {{0x2D30, 0x2D7F}}, ['Thai'] = {{0x0E00, 0x0E7F}}, ['Tibt'] = {{0x0F00, 0x0FFF}}, ['Vaii'] = {{0xA500, 0xA63F}}, ['Yiii'] = {{0xA000, 0xA48F}, {0xA490, 0xA4CF}} } Babel.script_blocks.Cyrs = Babel.script_blocks.Cyrl Babel.script_blocks.Hant = Babel.script_blocks.Hans Babel.script_blocks.Kana = Babel.script_blocks.Jpan function Babel.locale_map(head) if not Babel.locale_mapped then return head end local LOCALE = Babel.attr_locale local GLYPH = node.id('glyph') local inmath = false local toloc_save for item in node.traverse(head) do local toloc if not inmath and item.id == GLYPH then % Optimization: build a table with the chars found if Babel.chr_to_loc[item.char] then toloc = Babel.chr_to_loc[item.char] else for lc, maps in pairs(Babel.loc_to_scr) do for _, rg in pairs(maps) do if item.char >= rg[1] and item.char <= rg[2] then Babel.chr_to_loc[item.char] = lc toloc = lc break end end end end % Now, take action, but treat composite chars in a different % fashion, because they 'inherit' the previous locale. Not yet % optimized. if not toloc and (item.char >= 0x0300 and item.char <= 0x036F) or (item.char >= 0x1AB0 and item.char <= 0x1AFF) or (item.char >= 0x1DC0 and item.char <= 0x1DFF) then toloc = toloc_save end if toloc and toloc > -1 then if Babel.locale_props[toloc].lg then item.lang = Babel.locale_props[toloc].lg node.set_attribute(item, LOCALE, toloc) end if Babel.locale_props[toloc]['/'..item.font] then item.font = Babel.locale_props[toloc]['/'..item.font] end toloc_save = toloc end elseif not inmath and item.id == 7 then item.replace = item.replace and Babel.locale_map(item.replace) item.pre = item.pre and Babel.locale_map(item.pre) item.post = item.post and Babel.locale_map(item.post) elseif item.id == node.id'math' then inmath = (item.subtype == 0) end end return head end } \newcommand\babelcharproperty[1]{% \count@=#1\relax \ifvmode \expandafter\bbl@chprop \else \bbl@error{\string\babelcharproperty\space can be used only in\\% vertical mode (preamble or between paragraphs)}% {See the manual for futher info}% \fi} \newcommand\bbl@chprop[3][\the\count@]{% \@tempcnta=#1\relax \bbl@ifunset{bbl@chprop@#2}% {\bbl@error{No property named '#2'. Allowed values are\\% direction (bc), mirror (bmg), and linebreak (lb)}% {See the manual for futher info}}% {}% \loop \bbl@cs{chprop@#2}{#3}% \ifnum\count@<\@tempcnta \advance\count@\@ne \repeat} \def\bbl@chprop@direction#1{% \directlua{ Babel.characters[\the\count@] = Babel.characters[\the\count@] or {} Babel.characters[\the\count@]['d'] = '#1' }} \let\bbl@chprop@bc\bbl@chprop@direction \def\bbl@chprop@mirror#1{% \directlua{ Babel.characters[\the\count@] = Babel.characters[\the\count@] or {} Babel.characters[\the\count@]['m'] = '\number#1' }} \let\bbl@chprop@bmg\bbl@chprop@mirror \def\bbl@chprop@linebreak#1{% \directlua{ Babel.cjk_characters[\the\count@] = Babel.cjk_characters[\the\count@] or {} Babel.cjk_characters[\the\count@]['c'] = '#1' }} \let\bbl@chprop@lb\bbl@chprop@linebreak \def\bbl@chprop@locale#1{% \directlua{ Babel.chr_to_loc = Babel.chr_to_loc or {} Babel.chr_to_loc[\the\count@] = \bbl@ifblank{#1}{-1000}{\the\bbl@cs{id@@#1}}\space }} \directlua{ Babel.nohyphenation = \the\l@nohyphenation } \begingroup \catcode`\~=12 \catcode`\%=12 \catcode`\&=14 \catcode`\|=12 \gdef\babelprehyphenation{&% \@ifnextchar[{\bbl@settransform{0}}{\bbl@settransform{0}[]}} \gdef\babelposthyphenation{&% \@ifnextchar[{\bbl@settransform{1}}{\bbl@settransform{1}[]}} \gdef\bbl@settransform#1[#2]#3#4#5{&% \ifcase#1 \bbl@activateprehyphen \else \bbl@activateposthyphen \fi \begingroup \def\babeltempa{\bbl@add@list\babeltempb}&% \let\babeltempb\@empty \def\bbl@tempa{#5}&% \bbl@replace\bbl@tempa{,}{ ,}&% TODO. Ugly trick to preserve {} \expandafter\bbl@foreach\expandafter{\bbl@tempa}{&% \bbl@ifsamestring{##1}{remove}&% {\bbl@add@list\babeltempb{nil}}&% {\directlua{ local rep = [=[##1]=] rep = rep:gsub('^%s*(remove)%s*$', 'remove = true') rep = rep:gsub('^%s*(insert)%s*,', 'insert = true, ') rep = rep:gsub('(string)%s*=%s*([^%s,]*)', Babel.capture_func) if #1 == 0 then rep = rep:gsub('(space)%s*=%s*([%d%.]+)%s+([%d%.]+)%s+([%d%.]+)', 'space = {' .. '%2, %3, %4' .. '}') rep = rep:gsub('(spacefactor)%s*=%s*([%d%.]+)%s+([%d%.]+)%s+([%d%.]+)', 'spacefactor = {' .. '%2, %3, %4' .. '}') rep = rep:gsub('(kashida)%s*=%s*([^%s,]*)', Babel.capture_kashida) else rep = rep:gsub( '(no)%s*=%s*([^%s,]*)', Babel.capture_func) rep = rep:gsub( '(pre)%s*=%s*([^%s,]*)', Babel.capture_func) rep = rep:gsub( '(post)%s*=%s*([^%s,]*)', Babel.capture_func) end tex.print([[\string\babeltempa{{]] .. rep .. [[}}]]) }}}&% \let\bbl@kv@attribute\relax \let\bbl@kv@label\relax \bbl@forkv{#2}{\bbl@csarg\edef{kv@##1}{##2}}&% \ifx\bbl@kv@attribute\relax\else \edef\bbl@kv@attribute{\expandafter\bbl@stripslash\bbl@kv@attribute}&% \fi \directlua{ local lbkr = Babel.linebreaking.replacements[#1] local u = unicode.utf8 local id, attr, label if #1 == 0 then id = \the\csname bbl@id@@#3\endcsname\space else id = \the\csname l@#3\endcsname\space end \ifx\bbl@kv@attribute\relax attr = -1 \else attr = luatexbase.registernumber'\bbl@kv@attribute' \fi \ifx\bbl@kv@label\relax\else &% Same refs: label = [==[\bbl@kv@label]==] \fi &% Convert pattern: local patt = string.gsub([==[#4]==], '%s', '') if #1 == 0 then patt = string.gsub(patt, '|', ' ') end if not u.find(patt, '()', nil, true) then patt = '()' .. patt .. '()' end if #1 == 1 then patt = string.gsub(patt, '%(%)%^', '^()') patt = string.gsub(patt, '%$%(%)', '()$') end patt = u.gsub(patt, '{(.)}', function (n) return '%' .. (tonumber(n) and (tonumber(n)+1) or n) end) patt = u.gsub(patt, '{(%x%x%x%x+)}', function (n) return u.gsub(u.char(tonumber(n, 16)), '(%p)', '%%%1') end) lbkr[id] = lbkr[id] or {} table.insert(lbkr[id], { label=label, attr=attr, pattern=patt, replace={\babeltempb} }) }&% \endgroup} \endgroup \def\bbl@activateposthyphen{% \let\bbl@activateposthyphen\relax \directlua{ require('babel-transforms.lua') Babel.linebreaking.add_after(Babel.post_hyphenate_replace) }} \def\bbl@activateprehyphen{% \let\bbl@activateprehyphen\relax \directlua{ require('babel-transforms.lua') Babel.linebreaking.add_before(Babel.pre_hyphenate_replace) }} \def\bbl@activate@preotf{% \let\bbl@activate@preotf\relax % only once \directlua{ Babel = Babel or {} % function Babel.pre_otfload_v(head) if Babel.numbers and Babel.digits_mapped then head = Babel.numbers(head) end if Babel.bidi_enabled then head = Babel.bidi(head, false, dir) end return head end % function Babel.pre_otfload_h(head, gc, sz, pt, dir) if Babel.numbers and Babel.digits_mapped then head = Babel.numbers(head) end if Babel.bidi_enabled then head = Babel.bidi(head, false, dir) end return head end % luatexbase.add_to_callback('pre_linebreak_filter', Babel.pre_otfload_v, 'Babel.pre_otfload_v', luatexbase.priority_in_callback('pre_linebreak_filter', 'luaotfload.node_processor') or nil) % luatexbase.add_to_callback('hpack_filter', Babel.pre_otfload_h, 'Babel.pre_otfload_h', luatexbase.priority_in_callback('hpack_filter', 'luaotfload.node_processor') or nil) }} \ifnum\bbl@bidimode>100 \ifnum\bbl@bidimode<200 \let\bbl@beforeforeign\leavevmode \AtEndOfPackage{\EnableBabelHook{babel-bidi}} \RequirePackage{luatexbase} \bbl@activate@preotf \directlua{ require('babel-data-bidi.lua') \ifcase\expandafter\@gobbletwo\the\bbl@bidimode\or require('babel-bidi-basic.lua') \or require('babel-bidi-basic-r.lua') \fi} % TODO - to locale_props, not as separate attribute \newattribute\bbl@attr@dir \directlua{ Babel.attr_dir = luatexbase.registernumber'bbl@attr@dir' } % TODO. I don't like it, hackish: \bbl@exp{\output{\bodydir\pagedir\the\output}} \AtEndOfPackage{\EnableBabelHook{babel-bidi}} \fi\fi \chardef\bbl@thetextdir\z@ \chardef\bbl@thepardir\z@ \def\bbl@getluadir#1{% \directlua{ if tex.#1dir == 'TLT' then tex.sprint('0') elseif tex.#1dir == 'TRT' then tex.sprint('1') end}} \def\bbl@setluadir#1#2#3{% 1=text/par.. 2=\textdir.. 3=0 lr/1 rl \ifcase#3\relax \ifcase\bbl@getluadir{#1}\relax\else #2 TLT\relax \fi \else \ifcase\bbl@getluadir{#1}\relax #2 TRT\relax \fi \fi} \def\bbl@thedir{0} \def\bbl@textdir#1{% \bbl@setluadir{text}\textdir{#1}% \chardef\bbl@thetextdir#1\relax \edef\bbl@thedir{\the\numexpr\bbl@thepardir*3+#1}% \setattribute\bbl@attr@dir{\numexpr\bbl@thepardir*3+#1}} \def\bbl@pardir#1{% \bbl@setluadir{par}\pardir{#1}% \chardef\bbl@thepardir#1\relax} \def\bbl@bodydir{\bbl@setluadir{body}\bodydir} \def\bbl@pagedir{\bbl@setluadir{page}\pagedir} \def\bbl@dirparastext{\pardir\the\textdir\relax}% %%%% \ifnum\bbl@bidimode>\z@ \def\bbl@insidemath{0}% \def\bbl@everymath{\def\bbl@insidemath{1}} \def\bbl@everydisplay{\def\bbl@insidemath{2}} \frozen@everymath\expandafter{% \expandafter\bbl@everymath\the\frozen@everymath} \frozen@everydisplay\expandafter{% \expandafter\bbl@everydisplay\the\frozen@everydisplay} \AtBeginDocument{ \directlua{ function Babel.math_box_dir(head) if not (token.get_macro('bbl@insidemath') == '0') then if Babel.hlist_has_bidi(head) then local d = node.new(node.id'dir') d.dir = '+TRT' node.insert_before(head, node.has_glyph(head), d) for item in node.traverse(head) do node.set_attribute(item, Babel.attr_dir, token.get_macro('bbl@thedir')) end end end return head end luatexbase.add_to_callback("hpack_filter", Babel.math_box_dir, "Babel.math_box_dir", 0) }}% \fi \bbl@trace{Redefinitions for bidi layout} \def\BabelNoAMSMath{\let\bbl@noamsmath\relax} \ifnum\bbl@bidimode>\z@ \ifx\matheqdirmode\@undefined\else \matheqdirmode\@ne \fi \let\bbl@eqnodir\relax \def\bbl@eqdel{()} \def\bbl@eqnum{% {\normalfont\normalcolor \expandafter\@firstoftwo\bbl@eqdel \theequation \expandafter\@secondoftwo\bbl@eqdel}} \def\bbl@puteqno#1{\eqno\hbox{#1}} \def\bbl@putleqno#1{\leqno\hbox{#1}} \def\bbl@eqno@flip#1{% \ifdim\predisplaysize=-\maxdimen \eqno \hb@xt@.01pt{\hb@xt@\displaywidth{\hss{#1}}\hss}% \else \leqno\hbox{#1}% \fi} \def\bbl@leqno@flip#1{% \ifdim\predisplaysize=-\maxdimen \leqno \hb@xt@.01pt{\hss\hb@xt@\displaywidth{{#1}\hss}}% \else \eqno\hbox{#1}% \fi} \AtBeginDocument{% \ifx\maketag@@@\@undefined % Normal equation, eqnarray \AddToHook{env/equation/begin}{% \ifnum\bbl@thetextdir>\z@ \let\@eqnnum\bbl@eqnum \edef\bbl@eqnodir{\noexpand\bbl@textdir{\the\bbl@thetextdir}}% \chardef\bbl@thetextdir\z@ \bbl@add\normalfont{\bbl@eqnodir}% \ifcase\bbl@eqnpos \let\bbl@puteqno\bbl@eqno@flip \or \let\bbl@puteqno\bbl@leqno@flip \fi \fi}% \ifnum\bbl@eqnpos=\tw@\else \def\endequation{\bbl@puteqno{\@eqnnum}$$\@ignoretrue}% \fi \AddToHook{env/eqnarray/begin}{% \ifnum\bbl@thetextdir>\z@ \edef\bbl@eqnodir{\noexpand\bbl@textdir{\the\bbl@thetextdir}}% \chardef\bbl@thetextdir\z@ \bbl@add\normalfont{\bbl@eqnodir}% \ifnum\bbl@eqnpos=\@ne \def\@eqnnum{% \setbox\z@\hbox{\bbl@eqnum}% \hbox to0.01pt{\hss\hbox to\displaywidth{\box\z@\hss}}}% \else \let\@eqnnum\bbl@eqnum \fi \fi} % Hack. YA luatex bug?: \expandafter\bbl@sreplace\csname] \endcsname{$$}{\eqno\kern.001pt$$}% \else % amstex \ifx\bbl@noamsmath\@undefined \ifnum\bbl@eqnpos=\@ne \let\bbl@ams@lap\hbox \else \let\bbl@ams@lap\llap \fi \ExplSyntaxOn \bbl@sreplace\intertext@{\normalbaselines}% {\normalbaselines \ifx\bbl@eqnodir\relax\else\bbl@pardir\@ne\bbl@eqnodir\fi}% \ExplSyntaxOff \def\bbl@ams@tagbox#1#2{#1{\bbl@eqnodir#2}}% #1=hbox|@lap|flip \ifx\bbl@ams@lap\hbox % leqno \def\bbl@ams@flip#1{% \hbox to 0.01pt{\hss\hbox to\displaywidth{{#1}\hss}}}% \else % eqno \def\bbl@ams@flip#1{% \hbox to 0.01pt{\hbox to\displaywidth{\hss{#1}}\hss}}% \fi \def\bbl@ams@preset#1{% \ifnum\bbl@thetextdir>\z@ \edef\bbl@eqnodir{\noexpand\bbl@textdir{\the\bbl@thetextdir}}% \bbl@sreplace\textdef@{\hbox}{\bbl@ams@tagbox\hbox}% \bbl@sreplace\maketag@@@{\hbox}{\bbl@ams@tagbox#1}% \fi}% \ifnum\bbl@eqnpos=\tw@\else \def\bbl@ams@equation{% \ifnum\bbl@thetextdir>\z@ \edef\bbl@eqnodir{\noexpand\bbl@textdir{\the\bbl@thetextdir}}% \chardef\bbl@thetextdir\z@ \bbl@add\normalfont{\bbl@eqnodir}% \ifcase\bbl@eqnpos \def\veqno##1##2{\bbl@eqno@flip{##1##2}}% \or \def\veqno##1##2{\bbl@leqno@flip{##1##2}}% \fi \fi}% \AddToHook{env/equation/begin}{\bbl@ams@equation}% \AddToHook{env/equation*/begin}{\bbl@ams@equation}% \fi \AddToHook{env/cases/begin}{\bbl@ams@preset\bbl@ams@lap}% \AddToHook{env/multline/begin}{\bbl@ams@preset\hbox}% \AddToHook{env/gather/begin}{\bbl@ams@preset\bbl@ams@lap}% \AddToHook{env/gather*/begin}{\bbl@ams@preset\bbl@ams@lap}% \AddToHook{env/align/begin}{\bbl@ams@preset\bbl@ams@lap}% \AddToHook{env/align*/begin}{\bbl@ams@preset\bbl@ams@lap}% \AddToHook{env/eqnalign/begin}{\bbl@ams@preset\hbox}% % Hackish, for proper alignment. Don’t ask me why it works!: \bbl@exp{% Avoid a 'visible' conditional \\\AddToHook{env/align*/end}{\\\\\tag*{}\}}% \AddToHook{env/flalign/begin}{\bbl@ams@preset\hbox}% \AddToHook{env/split/before}{% \ifnum\bbl@thetextdir>\z@ \bbl@ifsamestring\@currenvir{equation}% {\ifx\bbl@ams@lap\hbox % leqno \def\bbl@ams@flip#1{% \hbox to 0.01pt{\hbox to\displaywidth{{#1}\hss}\hss}}% \else \def\bbl@ams@flip#1{% \hbox to 0.01pt{\hss\hbox to\displaywidth{\hss{#1}}}}% \fi}% {}% \fi}% \fi \fi} \fi \ifx\bbl@opt@layout\@nnil\endinput\fi % if no layout \ifnum\bbl@bidimode>\z@ \def\bbl@nextfake#1{% non-local changes, use always inside a group! \bbl@exp{% \def\\\bbl@insidemath{0}% \mathdir\the\bodydir #1% Once entered in math, set boxes to restore values \% \everyvbox{% \the\everyvbox \bodydir\the\bodydir \mathdir\the\mathdir \everyhbox{\the\everyhbox}% \everyvbox{\the\everyvbox}}% \everyhbox{% \the\everyhbox \bodydir\the\bodydir \mathdir\the\mathdir \everyhbox{\the\everyhbox}% \everyvbox{\the\everyvbox}}% \}}% \def\@hangfrom#1{% \setbox\@tempboxa\hbox{{#1}}% \hangindent\wd\@tempboxa \ifnum\bbl@getluadir{page}=\bbl@getluadir{par}\else \shapemode\@ne \fi \noindent\box\@tempboxa} \fi \IfBabelLayout{tabular} {\let\bbl@OL@@tabular\@tabular \bbl@replace\@tabular{$}{\bbl@nextfake$}% \let\bbl@NL@@tabular\@tabular \AtBeginDocument{% \ifx\bbl@NL@@tabular\@tabular\else \bbl@replace\@tabular{$}{\bbl@nextfake$}% \let\bbl@NL@@tabular\@tabular \fi}} {} \IfBabelLayout{lists} {\let\bbl@OL@list\list \bbl@sreplace\list{\parshape}{\bbl@listparshape}% \let\bbl@NL@list\list \def\bbl@listparshape#1#2#3{% \parshape #1 #2 #3 % \ifnum\bbl@getluadir{page}=\bbl@getluadir{par}\else \shapemode\tw@ \fi}} {} \IfBabelLayout{graphics} {\let\bbl@pictresetdir\relax \def\bbl@pictsetdir#1{% \ifcase\bbl@thetextdir \let\bbl@pictresetdir\relax \else \ifcase#1\bodydir TLT % Remember this sets the inner boxes \or\textdir TLT \else\bodydir TLT \textdir TLT \fi % \(text|par)dir required in pgf: \def\bbl@pictresetdir{\bodydir TRT\pardir TRT\textdir TRT\relax}% \fi}% \AddToHook{env/picture/begin}{\bbl@pictsetdir\tw@}% \directlua{ Babel.get_picture_dir = true Babel.picture_has_bidi = 0 % function Babel.picture_dir (head) if not Babel.get_picture_dir then return head end if Babel.hlist_has_bidi(head) then Babel.picture_has_bidi = 1 end return head end luatexbase.add_to_callback("hpack_filter", Babel.picture_dir, "Babel.picture_dir") }% \AtBeginDocument{% \long\def\put(#1,#2)#3{% \@killglue % Try: \ifx\bbl@pictresetdir\relax \def\bbl@tempc{0}% \else \directlua{ Babel.get_picture_dir = true Babel.picture_has_bidi = 0 }% \setbox\z@\hb@xt@\z@{% \@defaultunitsset\@tempdimc{#1}\unitlength \kern\@tempdimc #3\hss}% TODO: #3 executed twice (below). That’s bad. \edef\bbl@tempc{\directlua{tex.print(Babel.picture_has_bidi)}}% \fi % Do: \@defaultunitsset\@tempdimc{#2}\unitlength \raise\@tempdimc\hb@xt@\z@{% \@defaultunitsset\@tempdimc{#1}\unitlength \kern\@tempdimc {\ifnum\bbl@tempc>\z@\bbl@pictresetdir\fi#3}\hss}% \ignorespaces}% \MakeRobust\put}% \AtBeginDocument {\AddToHook{cmd/diagbox@pict/before}{\let\bbl@pictsetdir\@gobble}% \ifx\pgfpicture\@undefined\else % TODO. Allow deactivate? \AddToHook{env/pgfpicture/begin}{\bbl@pictsetdir\@ne}% \bbl@add\pgfinterruptpicture{\bbl@pictresetdir}% \bbl@add\pgfsys@beginpicture{\bbl@pictsetdir\z@}% \fi \ifx\tikzpicture\@undefined\else \AddToHook{env/tikzpicture/begin}{\bbl@pictsetdir\z@}% \bbl@add\tikz@atbegin@node{\bbl@pictresetdir}% \bbl@sreplace\tikz{\begingroup}{\begingroup\bbl@pictsetdir\tw@}% \fi \ifx\tcolorbox\@undefined\else \AddToHook{env/tcolorbox/begin}{\bbl@pictsetdir\@ne}% \bbl@sreplace\tcb@savebox {\ignorespaces}{\ignorespaces\bbl@pictresetdir}% \ifx\tikzpicture@tcb@hooked\@undefined\else \bbl@sreplace\tikzpicture@tcb@hooked{\noexpand\tikzpicture}% {\textdir TLT\noexpand\tikzpicture}% \fi \fi }} {} \IfBabelLayout{counters}% {\let\bbl@OL@@textsuperscript\@textsuperscript \bbl@sreplace\@textsuperscript{\m@th}{\m@th\mathdir\pagedir}% \let\bbl@latinarabic=\@arabic \let\bbl@OL@@arabic\@arabic \def\@arabic#1{\babelsublr{\bbl@latinarabic#1}}% \@ifpackagewith{babel}{bidi=default}% {\let\bbl@asciiroman=\@roman \let\bbl@OL@@roman\@roman \def\@roman#1{\babelsublr{\ensureascii{\bbl@asciiroman#1}}}% \let\bbl@asciiRoman=\@Roman \let\bbl@OL@@roman\@Roman \def\@Roman#1{\babelsublr{\ensureascii{\bbl@asciiRoman#1}}}% \let\bbl@OL@labelenumii\labelenumii \def\labelenumii{)\theenumii(}% \let\bbl@OL@p@enumiii\p@enumiii \def\p@enumiii{\p@enumii)\theenumii(}}{}}{} \bbl@trace{Bidi footnotes} \ifnum\bbl@bidimode>\z@ \def\bbl@footnote#1#2#3{% \@ifnextchar[% {\bbl@footnote@o{#1}{#2}{#3}}% {\bbl@footnote@x{#1}{#2}{#3}}} \long\def\bbl@footnote@x#1#2#3#4{% \bgroup \select@language@x{\bbl@main@language}% \bbl@fn@footnote{#2#1{\ignorespaces#4}#3}% \egroup} \long\def\bbl@footnote@o#1#2#3[#4]#5{% \bgroup \select@language@x{\bbl@main@language}% \bbl@fn@footnote[#4]{#2#1{\ignorespaces#5}#3}% \egroup} \def\bbl@footnotetext#1#2#3{% \@ifnextchar[% {\bbl@footnotetext@o{#1}{#2}{#3}}% {\bbl@footnotetext@x{#1}{#2}{#3}}} \long\def\bbl@footnotetext@x#1#2#3#4{% \bgroup \select@language@x{\bbl@main@language}% \bbl@fn@footnotetext{#2#1{\ignorespaces#4}#3}% \egroup} \long\def\bbl@footnotetext@o#1#2#3[#4]#5{% \bgroup \select@language@x{\bbl@main@language}% \bbl@fn@footnotetext[#4]{#2#1{\ignorespaces#5}#3}% \egroup} \def\BabelFootnote#1#2#3#4{% \ifx\bbl@fn@footnote\@undefined \let\bbl@fn@footnote\footnote \fi \ifx\bbl@fn@footnotetext\@undefined \let\bbl@fn@footnotetext\footnotetext \fi \bbl@ifblank{#2}% {\def#1{\bbl@footnote{\@firstofone}{#3}{#4}} \@namedef{\bbl@stripslash#1text}% {\bbl@footnotetext{\@firstofone}{#3}{#4}}}% {\def#1{\bbl@exp{\\\bbl@footnote{\\\foreignlanguage{#2}}}{#3}{#4}}% \@namedef{\bbl@stripslash#1text}% {\bbl@exp{\\\bbl@footnotetext{\\\foreignlanguage{#2}}}{#3}{#4}}}} \fi \IfBabelLayout{footnotes}% {\let\bbl@OL@footnote\footnote \BabelFootnote\footnote\languagename{}{}% \BabelFootnote\localfootnote\languagename{}{}% \BabelFootnote\mainfootnote{}{}{}} {} \IfBabelLayout{extras}% {\let\bbl@OL@underline\underline \bbl@sreplace\underline{$\@@underline}{\bbl@nextfake$\@@underline}% \let\bbl@OL@LaTeX2e\LaTeX2e \DeclareRobustCommand{\LaTeXe}{\mbox{\m@th \if b\expandafter\@car\f@series\@nil\boldmath\fi \babelsublr{% \LaTeX\kern.15em2\bbl@nextfake$_{\textstyle\varepsilon}$}}}} {} \endinput %% %% End of file `luababel.def'.