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.
1463 lines
49 KiB
1463 lines
49 KiB
%%
|
|
%% This is file `luababel.def',
|
|
%% generated with the docstrip utility.
|
|
%%
|
|
%% The original source files were:
|
|
%%
|
|
%% babel.dtx (with options: `luatex')
|
|
%%
|
|
%%
|
|
%% 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.
|
|
%%
|
|
|
|
\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
|
|
\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
|
|
}
|
|
\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 with \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,
|
|
luatexbase.registernumber'bbl@attr@locale')
|
|
local props = Babel.locale_props[LOCALE]
|
|
|
|
local class = Babel.cjk_class[item.char].c
|
|
|
|
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
|
|
|
|
quad = font.getfont(item.font).size
|
|
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@{\bbl@cl{lnbrk}}{c}%
|
|
\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}}
|
|
\AddBabelHook{babel-fontspec}{afterextras}{\bbl@switchfont}
|
|
\AddBabelHook{babel-fontspec}{beforestart}{\bbl@ckeckstdfonts}
|
|
\DisableBabelHook{babel-fontspec}
|
|
\bbl@trace{Font handling with fontspec}
|
|
\@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
|
|
\usepackage{fontspec}%
|
|
\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}}%
|
|
{\bbl@exp{%
|
|
\\\bbl@sreplace\<\bbl@tempb family >%
|
|
{\@nameuse{\bbl@tempb default}}{\<\bbl@tempb default>}}}%
|
|
% 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@\bbl@tempb dflt@\languagename>\<bbl@\bbl@tempb dflt@>%
|
|
\\\bbl@font@set\<bbl@\bbl@tempb dflt@\languagename>%
|
|
\<\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
|
|
\\\fontfamily\<#1default>\\\selectfont}%
|
|
\\\DeclareTextFontCommand{\<text#1>}{\<#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 no 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@##1dflt@\languagename>%
|
|
\<bbl@##1dflt@>}}}%
|
|
{\bbl@exp{% 2=T - from script
|
|
\global\let\<bbl@##1dflt@\languagename>%
|
|
\<bbl@##1dflt@*\bbl@tempa>}}}%
|
|
{}}% 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
|
|
\\\bbl@add\\\originalTeX{%
|
|
\\\bbl@font@rst{\bbl@cl{##1dflt}}%
|
|
\<##1default>\<##1family>{##1}}%
|
|
\\\bbl@font@set\<bbl@##1dflt@\languagename>% 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{%
|
|
\def\\#2{#1}% eg, \rmdefault{\bbl@rmdflt@lang}
|
|
\\\bbl@ifsamestring{#2}{\f@family}{\\#3\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 '
|
|
\<keys_if_exist:nnF>{fontspec-opentype}{Script/\bbl@cl{sname}}%
|
|
{\\\newfontscript{\bbl@cl{sname}}{\bbl@cl{sotf}}}%
|
|
\<keys_if_exist:nnF>{fontspec-opentype}{Language/\bbl@cl{lname}}%
|
|
{\\\newfontlanguage{\bbl@cl{lname}}{\bbl@cl{lotf}}}%
|
|
\\\renewfontfamily\\#4%
|
|
[\bbl@cs{lsys@\languagename},#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}
|
|
\newcommand\babelFSstore[2][]{%
|
|
\bbl@ifblank{#1}%
|
|
{\bbl@csarg\def{sname@#2}{Latin}}%
|
|
{\bbl@csarg\def{sname@#2}{#1}}%
|
|
\bbl@provide@dirs{#2}%
|
|
\bbl@csarg\ifnum{wdir@#2}>\z@
|
|
\let\bbl@beforeforeign\leavevmode
|
|
\EnableBabelHook{babel-bidi}%
|
|
\fi
|
|
\bbl@foreach{#2}{%
|
|
\bbl@FSstore{##1}{rm}\rmdefault\bbl@save@rmdefault
|
|
\bbl@FSstore{##1}{sf}\sfdefault\bbl@save@sfdefault
|
|
\bbl@FSstore{##1}{tt}\ttdefault\bbl@save@ttdefault}}
|
|
\def\bbl@FSstore#1#2#3#4{%
|
|
\bbl@csarg\edef{#2default#1}{#3}%
|
|
\expandafter\addto\csname extras#1\endcsname{%
|
|
\let#4#3%
|
|
\ifx#3\f@family
|
|
\edef#3{\csname bbl@#2default#1\endcsname}%
|
|
\fontfamily{#3}\selectfont
|
|
\else
|
|
\edef#3{\csname bbl@#2default#1\endcsname}%
|
|
\fi}%
|
|
\expandafter\addto\csname noextras#1\endcsname{%
|
|
\ifx#3\f@family
|
|
\fontfamily{#4}\selectfont
|
|
\fi
|
|
\let#3#4}}
|
|
\let\bbl@langfeatures\@empty
|
|
\def\babelFSfeatures{% make sure \fontspec is redefined once
|
|
\let\bbl@ori@fontspec\fontspec
|
|
\renewcommand\fontspec[1][]{%
|
|
\bbl@ori@fontspec[\bbl@langfeatures##1]}
|
|
\let\babelFSfeatures\bbl@FSfeatures
|
|
\babelFSfeatures}
|
|
\def\bbl@FSfeatures#1#2{%
|
|
\expandafter\addto\csname extras#1\endcsname{%
|
|
\babel@save\bbl@langfeatures
|
|
\edef\bbl@langfeatures{#2,}}}
|
|
\directlua{
|
|
Babel.script_blocks = {
|
|
['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 = luatexbase.registernumber'bbl@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
|
|
}}
|
|
\begingroup
|
|
\catcode`\#=12
|
|
\catcode`\%=12
|
|
\catcode`\&=14
|
|
\directlua{
|
|
Babel.linebreaking.post_replacements = {}
|
|
Babel.linebreaking.pre_replacements = {}
|
|
|
|
function Babel.str_to_nodes(fn, matches, base)
|
|
local n, head, last
|
|
if fn == nil then return nil end
|
|
for s in string.utfvalues(fn(matches)) do
|
|
if base.id == 7 then
|
|
base = base.replace
|
|
end
|
|
n = node.copy(base)
|
|
n.char = s
|
|
if not head then
|
|
head = n
|
|
else
|
|
last.next = n
|
|
end
|
|
last = n
|
|
end
|
|
return head
|
|
end
|
|
|
|
function Babel.fetch_word(head, funct)
|
|
local word_string = ''
|
|
local word_nodes = {}
|
|
local lang
|
|
local item = head
|
|
local inmath = false
|
|
|
|
while item do
|
|
|
|
if item.id == 29
|
|
and not(item.char == 124) &% ie, not |
|
|
and not(item.char == 61) &% ie, not =
|
|
and not inmath
|
|
and (item.lang == lang or lang == nil) then
|
|
lang = lang or item.lang
|
|
word_string = word_string .. unicode.utf8.char(item.char)
|
|
word_nodes[#word_nodes+1] = item
|
|
|
|
elseif item.id == 7 and item.subtype == 2 and not inmath then
|
|
word_string = word_string .. '='
|
|
word_nodes[#word_nodes+1] = item
|
|
|
|
elseif item.id == 7 and item.subtype == 3 and not inmath then
|
|
word_string = word_string .. '|'
|
|
word_nodes[#word_nodes+1] = item
|
|
|
|
elseif item.id == 11 and item.subtype == 0 then
|
|
inmath = true
|
|
|
|
elseif word_string == '' then
|
|
&% pass
|
|
|
|
else
|
|
return word_string, word_nodes, item, lang
|
|
end
|
|
|
|
item = item.next
|
|
end
|
|
end
|
|
|
|
function Babel.post_hyphenate_replace(head)
|
|
local u = unicode.utf8
|
|
local lbkr = Babel.linebreaking.post_replacements
|
|
local word_head = head
|
|
|
|
while true do
|
|
local w, wn, nw, lang = Babel.fetch_word(word_head)
|
|
if not lang then return head end
|
|
|
|
if not lbkr[lang] then
|
|
break
|
|
end
|
|
|
|
for k=1, #lbkr[lang] do
|
|
local p = lbkr[lang][k].pattern
|
|
local r = lbkr[lang][k].replace
|
|
|
|
while true do
|
|
local matches = { u.match(w, p) }
|
|
if #matches < 2 then break end
|
|
|
|
local first = table.remove(matches, 1)
|
|
local last = table.remove(matches, #matches)
|
|
|
|
&% Fix offsets, from bytes to unicode.
|
|
first = u.len(w:sub(1, first-1)) + 1
|
|
last = u.len(w:sub(1, last-1))
|
|
|
|
local new &% used when inserting and removing nodes
|
|
local changed = 0
|
|
|
|
&% This loop traverses the replace list and takes the
|
|
&% corresponding actions
|
|
for q = first, last do
|
|
local crep = r[q-first+1]
|
|
local char_node = wn[q]
|
|
local char_base = char_node
|
|
|
|
if crep and crep.data then
|
|
char_base = wn[crep.data+first-1]
|
|
end
|
|
|
|
if crep == {} then
|
|
break
|
|
elseif crep == nil then
|
|
changed = changed + 1
|
|
node.remove(head, char_node)
|
|
elseif crep and (crep.pre or crep.no or crep.post) then
|
|
changed = changed + 1
|
|
d = node.new(7, 0) &% (disc, discretionary)
|
|
d.pre = Babel.str_to_nodes(crep.pre, matches, char_base)
|
|
d.post = Babel.str_to_nodes(crep.post, matches, char_base)
|
|
d.replace = Babel.str_to_nodes(crep.no, matches, char_base)
|
|
d.attr = char_base.attr
|
|
if crep.pre == nil then &% TeXbook p96
|
|
d.penalty = crep.penalty or tex.hyphenpenalty
|
|
else
|
|
d.penalty = crep.penalty or tex.exhyphenpenalty
|
|
end
|
|
head, new = node.insert_before(head, char_node, d)
|
|
node.remove(head, char_node)
|
|
if q == 1 then
|
|
word_head = new
|
|
end
|
|
elseif crep and crep.string then
|
|
changed = changed + 1
|
|
local str = crep.string(matches)
|
|
if str == '' then
|
|
if q == 1 then
|
|
word_head = char_node.next
|
|
end
|
|
head, new = node.remove(head, char_node)
|
|
elseif char_node.id == 29 and u.len(str) == 1 then
|
|
char_node.char = string.utfvalue(str)
|
|
else
|
|
local n
|
|
for s in string.utfvalues(str) do
|
|
if char_node.id == 7 then
|
|
log('Automatic hyphens cannot be replaced, just removed.')
|
|
else
|
|
n = node.copy(char_base)
|
|
end
|
|
n.char = s
|
|
if q == 1 then
|
|
head, new = node.insert_before(head, char_node, n)
|
|
word_head = new
|
|
else
|
|
node.insert_before(head, char_node, n)
|
|
end
|
|
end
|
|
|
|
node.remove(head, char_node)
|
|
end &% string length
|
|
end &% if char and char.string
|
|
end &% for char in match
|
|
if changed > 20 then
|
|
texio.write('Too many changes. Ignoring the rest.')
|
|
elseif changed > 0 then
|
|
w, wn, nw = Babel.fetch_word(word_head)
|
|
end
|
|
|
|
end &% for match
|
|
end &% for patterns
|
|
word_head = nw
|
|
end &% for words
|
|
return head
|
|
end
|
|
|
|
&%%%
|
|
&% Preliminary code for \babelprehyphenation
|
|
&% TODO. Copypaste pattern. Merge with fetch_word
|
|
function Babel.fetch_subtext(head, funct)
|
|
local word_string = ''
|
|
local word_nodes = {}
|
|
local lang
|
|
local item = head
|
|
local inmath = false
|
|
|
|
while item do
|
|
|
|
if item.id == 29 then
|
|
local locale = node.get_attribute(item, Babel.attr_locale)
|
|
|
|
if not(item.char == 124) &% ie, not | = space
|
|
and not inmath
|
|
and (locale == lang or lang == nil) then
|
|
lang = lang or locale
|
|
word_string = word_string .. unicode.utf8.char(item.char)
|
|
word_nodes[#word_nodes+1] = item
|
|
end
|
|
|
|
if item == node.tail(head) then
|
|
item = nil
|
|
return word_string, word_nodes, item, lang
|
|
end
|
|
|
|
elseif item.id == 12 and item.subtype == 13 and not inmath then
|
|
word_string = word_string .. '|'
|
|
word_nodes[#word_nodes+1] = item
|
|
|
|
if item == node.tail(head) then
|
|
item = nil
|
|
return word_string, word_nodes, item, lang
|
|
end
|
|
|
|
elseif item.id == 11 and item.subtype == 0 then
|
|
inmath = true
|
|
|
|
elseif word_string == '' then
|
|
&% pass
|
|
|
|
else
|
|
return word_string, word_nodes, item, lang
|
|
end
|
|
|
|
item = item.next
|
|
end
|
|
end
|
|
|
|
&% TODO. Copypaste pattern. Merge with pre_hyphenate_replace
|
|
function Babel.pre_hyphenate_replace(head)
|
|
local u = unicode.utf8
|
|
local lbkr = Babel.linebreaking.pre_replacements
|
|
local word_head = head
|
|
|
|
while true do
|
|
local w, wn, nw, lang = Babel.fetch_subtext(word_head)
|
|
if not lang then return head end
|
|
|
|
if not lbkr[lang] then
|
|
break
|
|
end
|
|
|
|
for k=1, #lbkr[lang] do
|
|
local p = lbkr[lang][k].pattern
|
|
local r = lbkr[lang][k].replace
|
|
|
|
while true do
|
|
local matches = { u.match(w, p) }
|
|
if #matches < 2 then break end
|
|
|
|
local first = table.remove(matches, 1)
|
|
local last = table.remove(matches, #matches)
|
|
|
|
&% Fix offsets, from bytes to unicode.
|
|
first = u.len(w:sub(1, first-1)) + 1
|
|
last = u.len(w:sub(1, last-1))
|
|
|
|
local new &% used when inserting and removing nodes
|
|
local changed = 0
|
|
|
|
&% This loop traverses the replace list and takes the
|
|
&% corresponding actions
|
|
for q = first, last do
|
|
local crep = r[q-first+1]
|
|
local char_node = wn[q]
|
|
local char_base = char_node
|
|
|
|
if crep and crep.data then
|
|
char_base = wn[crep.data+first-1]
|
|
end
|
|
|
|
if crep == {} then
|
|
break
|
|
elseif crep == nil then
|
|
changed = changed + 1
|
|
node.remove(head, char_node)
|
|
elseif crep and crep.string then
|
|
changed = changed + 1
|
|
local str = crep.string(matches)
|
|
if str == '' then
|
|
if q == 1 then
|
|
word_head = char_node.next
|
|
end
|
|
head, new = node.remove(head, char_node)
|
|
elseif char_node.id == 29 and u.len(str) == 1 then
|
|
char_node.char = string.utfvalue(str)
|
|
else
|
|
local n
|
|
for s in string.utfvalues(str) do
|
|
if char_node.id == 7 then
|
|
log('Automatic hyphens cannot be replaced, just removed.')
|
|
else
|
|
n = node.copy(char_base)
|
|
end
|
|
n.char = s
|
|
if q == 1 then
|
|
head, new = node.insert_before(head, char_node, n)
|
|
word_head = new
|
|
else
|
|
node.insert_before(head, char_node, n)
|
|
end
|
|
end
|
|
|
|
node.remove(head, char_node)
|
|
end &% string length
|
|
end &% if char and char.string
|
|
end &% for char in match
|
|
if changed > 20 then
|
|
texio.write('Too many changes. Ignoring the rest.')
|
|
elseif changed > 0 then
|
|
&% For one-to-one can we modifiy directly the
|
|
&% values without re-fetching? Very likely.
|
|
w, wn, nw = Babel.fetch_subtext(word_head)
|
|
end
|
|
|
|
end &% for match
|
|
end &% for patterns
|
|
word_head = nw
|
|
end &% for words
|
|
return head
|
|
end
|
|
&%%% end of preliminary code for \babelprehyphenation
|
|
|
|
&% The following functions belong to the next macro
|
|
|
|
&% This table stores capture maps, numbered consecutively
|
|
Babel.capture_maps = {}
|
|
|
|
function Babel.capture_func(key, cap)
|
|
local ret = "[[" .. cap:gsub('{([0-9])}', "]]..m[%1]..[[") .. "]]"
|
|
ret = ret:gsub('{([0-9])|([^|]+)|(.-)}', Babel.capture_func_map)
|
|
ret = ret:gsub("%[%[%]%]%.%.", '')
|
|
ret = ret:gsub("%.%.%[%[%]%]", '')
|
|
return key .. [[=function(m) return ]] .. ret .. [[ end]]
|
|
end
|
|
|
|
function Babel.capt_map(from, mapno)
|
|
return Babel.capture_maps[mapno][from] or from
|
|
end
|
|
|
|
&% Handle the {n|abc|ABC} syntax in captures
|
|
function Babel.capture_func_map(capno, from, to)
|
|
local froms = {}
|
|
for s in string.utfcharacters(from) do
|
|
table.insert(froms, s)
|
|
end
|
|
local cnt = 1
|
|
table.insert(Babel.capture_maps, {})
|
|
local mlen = table.getn(Babel.capture_maps)
|
|
for s in string.utfcharacters(to) do
|
|
Babel.capture_maps[mlen][froms[cnt]] = s
|
|
cnt = cnt + 1
|
|
end
|
|
return "]]..Babel.capt_map(m[" .. capno .. "]," ..
|
|
(mlen) .. ").." .. "[["
|
|
end
|
|
}
|
|
\catcode`\#=6
|
|
\gdef\babelposthyphenation#1#2#3{&%
|
|
\bbl@activateposthyphen
|
|
\begingroup
|
|
\def\babeltempa{\bbl@add@list\babeltempb}&%
|
|
\let\babeltempb\@empty
|
|
\bbl@foreach{#3}{&%
|
|
\bbl@ifsamestring{##1}{remove}&%
|
|
{\bbl@add@list\babeltempb{nil}}&%
|
|
{\directlua{
|
|
local rep = [[##1]]
|
|
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)
|
|
rep = rep:gsub('(string)%s*=%s*([^%s,]*)', Babel.capture_func)
|
|
tex.print([[\string\babeltempa{{]] .. rep .. [[}}]])
|
|
}}}&%
|
|
\directlua{
|
|
local lbkr = Babel.linebreaking.post_replacements
|
|
local u = unicode.utf8
|
|
&% Convert pattern:
|
|
local patt = string.gsub([==[#2]==], '%s', '')
|
|
if not u.find(patt, '()', nil, true) then
|
|
patt = '()' .. patt .. '()'
|
|
end
|
|
patt = u.gsub(patt, '{(.)}',
|
|
function (n)
|
|
return '%' .. (tonumber(n) and (tonumber(n)+1) or n)
|
|
end)
|
|
lbkr[\the\csname l@#1\endcsname] = lbkr[\the\csname l@#1\endcsname] or {}
|
|
table.insert(lbkr[\the\csname l@#1\endcsname],
|
|
{ pattern = patt, replace = { \babeltempb } })
|
|
}&%
|
|
\endgroup}
|
|
\gdef\babelprehyphenation#1#2#3{&%
|
|
\bbl@activateprehyphen
|
|
\begingroup
|
|
\def\babeltempa{\bbl@add@list\babeltempb}&%
|
|
\let\babeltempb\@empty
|
|
\bbl@foreach{#3}{&%
|
|
\bbl@ifsamestring{##1}{remove}&%
|
|
{\bbl@add@list\babeltempb{nil}}&%
|
|
{\directlua{
|
|
local rep = [[##1]]
|
|
rep = rep:gsub('(string)%s*=%s*([^%s,]*)', Babel.capture_func)
|
|
tex.print([[\string\babeltempa{{]] .. rep .. [[}}]])
|
|
}}}&%
|
|
\directlua{
|
|
local lbkr = Babel.linebreaking.pre_replacements
|
|
local u = unicode.utf8
|
|
&% Convert pattern:
|
|
local patt = string.gsub([==[#2]==], '%s', '')
|
|
if not u.find(patt, '()', nil, true) then
|
|
patt = '()' .. patt .. '()'
|
|
end
|
|
patt = u.gsub(patt, '{(.)}',
|
|
function (n)
|
|
return '%' .. (tonumber(n) and (tonumber(n)+1) or n)
|
|
end)
|
|
lbkr[\the\csname bbl@id@@#1\endcsname] = lbkr[\the\csname bbl@id@@#1\endcsname] or {}
|
|
table.insert(lbkr[\the\csname bbl@id@@#1\endcsname],
|
|
{ pattern = patt, replace = { \babeltempb } })
|
|
}&%
|
|
\endgroup}
|
|
\endgroup
|
|
\def\bbl@activateposthyphen{%
|
|
\let\bbl@activateposthyphen\relax
|
|
\directlua{
|
|
Babel.linebreaking.add_after(Babel.post_hyphenate_replace)
|
|
}}
|
|
\def\bbl@activateprehyphen{%
|
|
\let\bbl@activateprehyphen\relax
|
|
\directlua{
|
|
Babel.linebreaking.add_before(Babel.pre_hyphenate_replace)
|
|
}}
|
|
\bbl@trace{Redefinitions for bidi layout}
|
|
\ifx\@eqnnum\@undefined\else
|
|
\ifx\bbl@attr@dir\@undefined\else
|
|
\edef\@eqnnum{{%
|
|
\unexpanded{\ifcase\bbl@attr@dir\else\bbl@textdir\@ne\fi}%
|
|
\unexpanded\expandafter{\@eqnnum}}}
|
|
\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{%
|
|
\mathdir\the\bodydir
|
|
#1% Once entered in math, set boxes to restore values
|
|
\<ifmmode>%
|
|
\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}}%
|
|
\<fi>}}%
|
|
\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{%
|
|
\ifcase\bbl@thetextdir
|
|
\let\bbl@pictresetdir\relax
|
|
\else
|
|
\textdir TLT\relax
|
|
\def\bbl@pictresetdir{\textdir TRT\relax}%
|
|
\fi}%
|
|
\let\bbl@OL@@picture\@picture
|
|
\let\bbl@OL@put\put
|
|
\bbl@sreplace\@picture{\hskip-}{\bbl@pictsetdir\hskip-}%
|
|
\def\put(#1,#2)#3{% Not easy to patch. Better redefine.
|
|
\@killglue
|
|
\raise#2\unitlength
|
|
\hb@xt@\z@{\kern#1\unitlength{\bbl@pictresetdir#3}\hss}}%
|
|
\AtBeginDocument
|
|
{\ifx\tikz@atbegin@node\@undefined\else
|
|
\let\bbl@OL@pgfpicture\pgfpicture
|
|
\bbl@sreplace\pgfpicture{\pgfpicturetrue}{\bbl@pictsetdir\pgfpicturetrue}%
|
|
\bbl@add\pgfsys@beginpicture{\bbl@pictsetdir}%
|
|
\bbl@add\tikz@atbegin@node{\bbl@pictresetdir}%
|
|
\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}}}
|
|
\def\bbl@footnote@x#1#2#3#4{%
|
|
\bgroup
|
|
\select@language@x{\bbl@main@language}%
|
|
\bbl@fn@footnote{#2#1{\ignorespaces#4}#3}%
|
|
\egroup}
|
|
\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}}}
|
|
\def\bbl@footnotetext@x#1#2#3#4{%
|
|
\bgroup
|
|
\select@language@x{\bbl@main@language}%
|
|
\bbl@fn@footnotetext{#2#1{\ignorespaces#4}#3}%
|
|
\egroup}
|
|
\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'.
|
|
|