summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/generic/babel/babel-transforms.lua
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex/generic/babel/babel-transforms.lua')
-rw-r--r--Master/texmf-dist/tex/generic/babel/babel-transforms.lua511
1 files changed, 511 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/generic/babel/babel-transforms.lua b/Master/texmf-dist/tex/generic/babel/babel-transforms.lua
new file mode 100644
index 00000000000..ab6e7bc9daf
--- /dev/null
+++ b/Master/texmf-dist/tex/generic/babel/babel-transforms.lua
@@ -0,0 +1,511 @@
+--
+-- This is file `babel-transforms.lua',
+-- generated with the docstrip utility.
+--
+-- The original source files were:
+--
+-- babel.dtx (with options: `transforms')
+--
+--
+-- Copyright (C) 2012-2021 Javier Bezos and Johannes L. Braams.
+-- Copyright (C) 1989-2012 Johannes L. Braams and
+-- any individual authors listed elsewhere in this file.
+-- All rights reserved.
+--
+--
+-- This file is part of the Babel system.
+-- --------------------------------------
+--
+-- It may be distributed and/or modified under the
+-- conditions of the LaTeX Project Public License, either version 1.3
+-- of this license or (at your option) any later version.
+-- The latest version of this license is in
+-- http://www.latex-project.org/lppl.txt
+-- and version 1.3 or later is part of all distributions of LaTeX
+-- version 2003/12/01 or later.
+--
+-- This work has the LPPL maintenance status "maintained".
+--
+-- The Current Maintainer of this work is Javier Bezos.
+--
+-- The list of derived (unpacked) files belonging to the distribution
+-- and covered by LPPL is defined by the unpacking scripts (with
+-- extension |.ins|) which are part of the distribution.
+--
+
+Babel.linebreaking.replacements = {}
+Babel.linebreaking.replacements[0] = {} -- pre
+Babel.linebreaking.replacements[1] = {} -- post
+
+-- Discretionaries contain strings as nodes
+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
+
+Babel.fetch_subtext = {}
+
+Babel.ignore_pre_char = function(node)
+ return (node.lang == Babel.nohyphenation)
+end
+
+-- Merging both functions doesn't seen feasible, because there are too
+-- many differences.
+Babel.fetch_subtext[0] = function(head)
+ local word_string = ''
+ local word_nodes = {}
+ local lang
+ local item = head
+ local inmath = false
+
+ while item do
+
+ if item.id == 11 then
+ inmath = (item.subtype == 0)
+ end
+
+ if inmath then
+ -- pass
+
+ elseif item.id == 29 then
+ local locale = node.get_attribute(item, Babel.attr_locale)
+
+ if lang == locale or lang == nil then
+ lang = lang or locale
+ if Babel.ignore_pre_char(item) then
+ word_string = word_string .. Babel.us_char
+ else
+ word_string = word_string .. unicode.utf8.char(item.char)
+ end
+ word_nodes[#word_nodes+1] = item
+ else
+ break
+ end
+
+ elseif item.id == 12 and item.subtype == 13 then
+ word_string = word_string .. ' '
+ word_nodes[#word_nodes+1] = item
+
+ -- Ignore leading unrecognized nodes, too.
+ elseif word_string ~= '' then
+ word_string = word_string .. Babel.us_char
+ word_nodes[#word_nodes+1] = item -- Will be ignored
+ end
+
+ item = item.next
+ end
+
+ -- Here and above we remove some trailing chars but not the
+ -- corresponding nodes. But they aren't accessed.
+ if word_string:sub(-1) == ' ' then
+ word_string = word_string:sub(1,-2)
+ end
+ word_string = unicode.utf8.gsub(word_string, Babel.us_char .. '+$', '')
+ return word_string, word_nodes, item, lang
+end
+
+Babel.fetch_subtext[1] = function(head)
+ local word_string = ''
+ local word_nodes = {}
+ local lang
+ local item = head
+ local inmath = false
+
+ while item do
+
+ if item.id == 11 then
+ inmath = (item.subtype == 0)
+ end
+
+ if inmath then
+ -- pass
+
+ elseif item.id == 29 then
+ if item.lang == lang or lang == nil then
+ if (item.char ~= 124) and (item.char ~= 61) then -- not =, not |
+ lang = lang or item.lang
+ word_string = word_string .. unicode.utf8.char(item.char)
+ word_nodes[#word_nodes+1] = item
+ end
+ else
+ break
+ end
+
+ elseif item.id == 7 and item.subtype == 2 then
+ word_string = word_string .. '='
+ word_nodes[#word_nodes+1] = item
+
+ elseif item.id == 7 and item.subtype == 3 then
+ word_string = word_string .. '|'
+ word_nodes[#word_nodes+1] = item
+
+ -- (1) Go to next word if nothing was found, and (2) implicitly
+ -- remove leading USs.
+ elseif word_string == '' then
+ -- pass
+
+ -- This is the responsible for splitting by words.
+ elseif (item.id == 12 and item.subtype == 13) then
+ break
+
+ else
+ word_string = word_string .. Babel.us_char
+ word_nodes[#word_nodes+1] = item -- Will be ignored
+ end
+
+ item = item.next
+ end
+
+ word_string = unicode.utf8.gsub(word_string, Babel.us_char .. '+$', '')
+ return word_string, word_nodes, item, lang
+end
+
+function Babel.pre_hyphenate_replace(head)
+ Babel.hyphenate_replace(head, 0)
+end
+
+function Babel.post_hyphenate_replace(head)
+ Babel.hyphenate_replace(head, 1)
+end
+
+Babel.us_char = string.char(31)
+
+function Babel.hyphenate_replace(head, mode)
+ local u = unicode.utf8
+ local lbkr = Babel.linebreaking.replacements[mode]
+
+ local word_head = head
+
+ while true do -- for each subtext block
+
+ local w, w_nodes, nw, lang = Babel.fetch_subtext[mode](word_head)
+
+ if Babel.debug then
+ print()
+ print((mode == 0) and '@@@@<' or '@@@@>', w)
+ end
+
+ if nw == nil and w == '' then break end
+
+ if not lang then goto next end
+ if not lbkr[lang] then goto next end
+
+ -- For each saved (pre|post)hyphenation. TODO. Reconsider how
+ -- loops are nested.
+ for k=1, #lbkr[lang] do
+ local p = lbkr[lang][k].pattern
+ local r = lbkr[lang][k].replace
+
+ if Babel.debug then
+ print('*****', p, mode)
+ end
+
+ -- This variable is set in some cases below to the first *byte*
+ -- after the match, either as found by u.match (faster) or the
+ -- computed position based on sc if w has changed.
+ local last_match = 0
+ local step = 0
+
+ -- For every match.
+ while true do
+ if Babel.debug then
+ print('=====')
+ end
+ local new -- used when inserting and removing nodes
+
+ local matches = { u.match(w, p, last_match) }
+
+ if #matches < 2 then break end
+
+ -- Get and remove empty captures (with ()'s, which return a
+ -- number with the position), and keep actual captures
+ -- (from (...)), if any, in matches.
+ local first = table.remove(matches, 1)
+ local last = table.remove(matches, #matches)
+ -- Non re-fetched substrings may contain \31, which separates
+ -- subsubstrings.
+ if string.find(w:sub(first, last-1), Babel.us_char) then break end
+
+ local save_last = last -- with A()BC()D, points to D
+
+ -- Fix offsets, from bytes to unicode. Explained above.
+ first = u.len(w:sub(1, first-1)) + 1
+ last = u.len(w:sub(1, last-1)) -- now last points to C
+
+ -- This loop stores in n small table the nodes
+ -- corresponding to the pattern. Used by 'data' to provide a
+ -- predictable behavior with 'insert' (now w_nodes is modified on
+ -- the fly), and also access to 'remove'd nodes.
+ local sc = first-1 -- Used below, too
+ local data_nodes = {}
+
+ for q = 1, last-first+1 do
+ data_nodes[q] = w_nodes[sc+q]
+ end
+
+ -- This loop traverses the matched substring and takes the
+ -- corresponding action stored in the replacement list.
+ -- sc = the position in substr nodes / string
+ -- rc = the replacement table index
+ local rc = 0
+
+ while rc < last-first+1 do -- for each replacement
+ if Babel.debug then
+ print('.....', rc + 1)
+ end
+ sc = sc + 1
+ rc = rc + 1
+
+ if Babel.debug then
+ Babel.debug_hyph(w, w_nodes, sc, first, last, last_match)
+ local ss = ''
+ for itt in node.traverse(head) do
+ if itt.id == 29 then
+ ss = ss .. unicode.utf8.char(itt.char)
+ else
+ ss = ss .. '{' .. itt.id .. '}'
+ end
+ end
+ print('*****************', ss)
+
+ end
+
+ local crep = r[rc]
+ local item = w_nodes[sc]
+ local item_base = item
+ local placeholder = Babel.us_char
+ local d
+
+ if crep and crep.data then
+ item_base = data_nodes[crep.data]
+ end
+
+ if crep then
+ step = crep.step or 0
+ end
+
+ if crep and next(crep) == nil then -- = {}
+ last_match = save_last -- Optimization
+ goto next
+
+ elseif crep == nil or crep.remove then
+ node.remove(head, item)
+ table.remove(w_nodes, sc)
+ w = u.sub(w, 1, sc-1) .. u.sub(w, sc+1)
+ sc = sc - 1 -- Nothing has been inserted.
+ last_match = utf8.offset(w, sc+1+step)
+ goto next
+
+ elseif crep and crep.kashida then -- Experimental
+ node.set_attribute(item,
+ Babel.attr_kashida,
+ crep.kashida)
+ last_match = utf8.offset(w, sc+1+step)
+ goto next
+
+ elseif crep and crep.string then
+ local str = crep.string(matches)
+ if str == '' then -- Gather with nil
+ node.remove(head, item)
+ table.remove(w_nodes, sc)
+ w = u.sub(w, 1, sc-1) .. u.sub(w, sc+1)
+ sc = sc - 1 -- Nothing has been inserted.
+ else
+ local loop_first = true
+ for s in string.utfvalues(str) do
+ d = node.copy(item_base)
+ d.char = s
+ if loop_first then
+ loop_first = false
+ head, new = node.insert_before(head, item, d)
+ if sc == 1 then
+ word_head = head
+ end
+ w_nodes[sc] = d
+ w = u.sub(w, 1, sc-1) .. u.char(s) .. u.sub(w, sc+1)
+ else
+ sc = sc + 1
+ head, new = node.insert_before(head, item, d)
+ table.insert(w_nodes, sc, new)
+ w = u.sub(w, 1, sc-1) .. u.char(s) .. u.sub(w, sc)
+ end
+ if Babel.debug then
+ print('.....', 'str')
+ Babel.debug_hyph(w, w_nodes, sc, first, last, last_match)
+ end
+ end -- for
+ node.remove(head, item)
+ end -- if ''
+ last_match = utf8.offset(w, sc+1+step)
+ goto next
+
+ elseif mode == 1 and crep and (crep.pre or crep.no or crep.post) then
+ d = node.new(7, 0) -- (disc, discretionary)
+ d.pre = Babel.str_to_nodes(crep.pre, matches, item_base)
+ d.post = Babel.str_to_nodes(crep.post, matches, item_base)
+ d.replace = Babel.str_to_nodes(crep.no, matches, item_base)
+ d.attr = item_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
+ placeholder = '|'
+ head, new = node.insert_before(head, item, d)
+
+ elseif mode == 0 and crep and (crep.pre or crep.no or crep.post) then
+ -- ERROR
+
+ elseif crep and crep.penalty then
+ d = node.new(14, 0) -- (penalty, userpenalty)
+ d.attr = item_base.attr
+ d.penalty = crep.penalty
+ head, new = node.insert_before(head, item, d)
+
+ elseif crep and crep.space then
+ -- 655360 = 10 pt = 10 * 65536 sp
+ d = node.new(12, 13) -- (glue, spaceskip)
+ local quad = font.getfont(item_base.font).size or 655360
+ node.setglue(d, crep.space[1] * quad,
+ crep.space[2] * quad,
+ crep.space[3] * quad)
+ if mode == 0 then
+ placeholder = ' '
+ end
+ head, new = node.insert_before(head, item, d)
+
+ elseif crep and crep.spacefactor then
+ d = node.new(12, 13) -- (glue, spaceskip)
+ local base_font = font.getfont(item_base.font)
+ node.setglue(d,
+ crep.spacefactor[1] * base_font.parameters['space'],
+ crep.spacefactor[2] * base_font.parameters['space_stretch'],
+ crep.spacefactor[3] * base_font.parameters['space_shrink'])
+ if mode == 0 then
+ placeholder = ' '
+ end
+ head, new = node.insert_before(head, item, d)
+
+ elseif mode == 0 and crep and crep.space then
+ -- ERROR
+
+ end -- ie replacement cases
+
+ -- Shared by disc, space and penalty.
+ if sc == 1 then
+ word_head = head
+ end
+ if crep.insert then
+ w = u.sub(w, 1, sc-1) .. placeholder .. u.sub(w, sc)
+ table.insert(w_nodes, sc, new)
+ last = last + 1
+ else
+ w_nodes[sc] = d
+ node.remove(head, item)
+ w = u.sub(w, 1, sc-1) .. placeholder .. u.sub(w, sc+1)
+ end
+
+ last_match = utf8.offset(w, sc+1+step)
+
+ ::next::
+
+ end -- for each replacement
+
+ if Babel.debug then
+ print('.....', '/')
+ Babel.debug_hyph(w, w_nodes, sc, first, last, last_match)
+ end
+
+ end -- for match
+
+ end -- for patterns
+
+ ::next::
+ word_head = nw
+ end -- for substring
+ return head
+end
+
+-- This table stores capture maps, numbered consecutively
+Babel.capture_maps = {}
+
+-- The following functions belong to the next macro
+function Babel.capture_func(key, cap)
+ local ret = "[[" .. cap:gsub('{([0-9])}', "]]..m[%1]..[[") .. "]]"
+ local cnt
+ local u = unicode.utf8
+ ret, cnt = ret:gsub('{([0-9])|([^|]+)|(.-)}', Babel.capture_func_map)
+ if cnt == 0 then
+ ret = u.gsub(ret, '{(%x%x%x%x+)}',
+ function (n)
+ return u.char(tonumber(n, 16))
+ end)
+ end
+ 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 u = unicode.utf8
+ from = u.gsub(from, '{(%x%x%x%x+)}',
+ function (n)
+ return u.char(tonumber(n, 16))
+ end)
+ to = u.gsub(to, '{(%x%x%x%x+)}',
+ function (n)
+ return u.char(tonumber(n, 16))
+ end)
+ 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
+
+-- Create/Extend reversed sorted list of kashida weights:
+function Babel.capture_kashida(key, wt)
+ wt = tonumber(wt)
+ if Babel.kashida_wts then
+ for p, q in ipairs(Babel.kashida_wts) do
+ if wt == q then
+ break
+ elseif wt > q then
+ table.insert(Babel.kashida_wts, p, wt)
+ break
+ elseif table.getn(Babel.kashida_wts) == p then
+ table.insert(Babel.kashida_wts, wt)
+ end
+ end
+ else
+ Babel.kashida_wts = { wt }
+ end
+ return 'kashida = ' .. wt
+end